คำนวณเวลาดำเนินการของวิธีการ


533

สำเนาซ้ำที่เป็นไปได้:
ฉันจะวัดระยะเวลาที่ฟังก์ชันใช้งานได้อย่างไร

ฉันมีวิธีการจับเวลา I / O ซึ่งคัดลอกข้อมูลจากที่ตั้งไปยังที่อื่น เป็นวิธีที่ดีที่สุดและจริงมากที่สุดในการคำนวณเวลาดำเนินการ? Thread? Timer? Stopwatch? ทางออกอื่น ๆ ? ฉันต้องการหนึ่งที่แน่นอนที่สุดและสั้นที่สุดเท่าที่จะทำได้

คำตอบ:


1131

Stopwatch ได้รับการออกแบบมาเพื่อจุดประสงค์นี้และเป็นหนึ่งในวิธีที่ดีที่สุดในการวัดเวลาดำเนินการใน. NET

var watch = System.Diagnostics.Stopwatch.StartNew();
// the code that you want to measure comes here
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

ห้ามใช้ DateTimeเพื่อวัดเวลาดำเนินการใน. NET


UPDATE:

ตามที่ระบุโดย @ series0ne ในส่วนความคิดเห็น: หากคุณต้องการการวัดที่แม่นยำของการประมวลผลของรหัสบางอย่างคุณจะต้องใช้เคาน์เตอร์วัดประสิทธิภาพที่สร้างไว้ในระบบปฏิบัติการ คำตอบต่อไปนี้มีภาพรวมที่ดี


2
ตรงและสิ่งที่เกี่ยวกับกรณีนี้: ฉันมีวง foreach ที่มีThreadPool.QueueUserWorkItem(delegate { CopyFiles(folder, dest); }); ภายใน แต่นาฬิกาจับเวลาหยุดก่อนที่จะทำทุกอย่าง
Mahdi Tahsildari

13
@DarinDimitrov - นาฬิกาจับเวลาไม่ถูกต้องทั้งหมดหรือไม่ โปรดจำไว้ว่าสัญญาณรบกวนพื้นหลัง. NET (เช่น JITing) ทำให้เวลาในการประมวลผลที่แตกต่างกันเกิดขึ้น ดังนั้นตามความเป็นจริงสำหรับการวัดที่แม่นยำ OP ควรใช้ profiler ของประสิทธิภาพ
Matthew Layton

3
@ series0ne จุดดีมาก ฉันจะอัปเดตคำตอบของฉันเพื่อรวมความคิดเห็นที่มีค่าของคุณ
ดารินทร์ดิมิทรอฟ

7
@DarinDimitrov ฉันเพิ่งได้สัมภาษณ์กับนักพัฒนาอาวุโสที่มีทักษะสูงมาก เขาชี้ให้ฉันเห็นว่าการใช้ DateTimes นั้นแม่นยำกว่าการใช้ StopWatch เขากล่าวว่าเหตุผลในการนี้คือ Stopwatch ใน. NET ไม่ได้คำนึงถึงความเกี่ยวข้องของ CPU ดังนั้นหากเธรดของคุณย้ายจากแกนหนึ่งไปยังอีกแกนหลัก StopWatch จะไม่คำนึงถึงเวลาดำเนินการของแกนกลางอื่น ๆ เฉพาะเธรดที่เริ่มต้นการเรียกใช้งาน คุณมีความคิดเห็นอย่างไรกับเรื่องนี้?
Matthew Layton

2
@ series0ne สิ่งที่ผู้พัฒนาอาวุโสบอกคุณเกี่ยวกับนาฬิกาจับเวลาและวันที่เวลาเป็นจริงอย่างแน่นอน ยกเว้นว่าด้วย DateTime คุณมีความแม่นยำไม่เพียงพอ ปัญหาคือไม่มีคลาสดังกล่าวใน. NET ที่จะช่วยให้คุณมีคุณสมบัติเหล่านั้นทั้งหมด
ดารินทินดิมิทรอฟ

75

จากประสบการณ์ส่วนตัวSystem.Diagnostics.Stopwatchชั้นเรียนสามารถใช้ในการวัดเวลาดำเนินการของวิธีการอย่างไรก็ตามระวัง : มันไม่ถูกต้องทั้งหมด!

ลองพิจารณาตัวอย่างต่อไปนี้:

Stopwatch sw;

for(int index = 0; index < 10; index++)
{
    sw = Stopwatch.StartNew();
    DoSomething();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

sw.Stop();

ตัวอย่างผลลัพธ์

132ms
4ms
3ms
3ms
2ms
3ms
34ms
2ms
1ms
1ms

ตอนนี้คุณกำลังสงสัย "ทำไมถึงใช้เวลา 132 มิลลิวินาทีในครั้งแรกและใช้เวลาที่เหลือน้อยลงอย่างเห็นได้ชัด"

คำตอบคือStopwatchไม่ชดเชยกิจกรรม "เสียงรบกวนรอบข้าง" ใน. NET เช่น JITing ดังนั้นเป็นครั้งแรกที่คุณเรียกใช้วิธีการของคุณ. NET JIT เป็นครั้งแรก เวลาที่ใช้ในการทำเช่นนี้จะถูกเพิ่มเข้ากับเวลาของการดำเนินการ ปัจจัยอื่น ๆ เช่นกันจะทำให้เวลาดำเนินการแตกต่างกัน

สิ่งที่คุณควรมองหาความแม่นยำแน่นอนคือการทำโปรไฟล์ประสิทธิภาพ !

ดูที่ต่อไปนี้:

RedGate ANTS Performance Profiler เป็นผลิตภัณฑ์เชิงพาณิชย์ แต่ให้ผลลัพธ์ที่แม่นยำมาก - เพิ่มประสิทธิภาพของแอพพลิเคชั่นของคุณด้วย. NET Profiling

นี่คือบทความ StackOverflow ในการทำโปรไฟล์: - Profilers. NET ที่ดีคืออะไร

ฉันได้เขียนบทความเกี่ยวกับการทำโปรไฟล์ประสิทธิภาพด้วยนาฬิกาจับเวลาที่คุณอาจต้องการดู - การทำโปรไฟล์ประสิทธิภาพใน. NET


2
@mahditahsildari ไม่มีปัญหา ดีใจที่ฉันสามารถช่วย! :-)
Matthew Layton

41
ผมไม่แน่ใจว่าทำไมนี้เป็นตัวอย่างของความไม่ถูกต้อง นาฬิกาจับเวลาทำการวัดค่าใช้จ่ายโดยรวมของการโทรครั้งแรกอย่างแม่นยำซึ่งเป็นสิ่งที่เกี่ยวข้องกับลูกค้าที่กำลังใช้งานรหัสนี้ พวกเขาไม่สนใจว่า 132 มิลลิวินาทีเหล่านั้นจะถูกเรียกเก็บเงินจากการดำเนินการตามวิธีการหรือการกระวนกระวายใจพวกเขาสนใจเวลาทั้งหมดที่ผ่านไป
Eric Lippert

2
@ series0ne หากคุณสนใจเกี่ยวกับประสิทธิภาพของลูปแล้วให้วัดประสิทธิภาพของลูป อย่าเพิ่งคิดว่าการทำบางสิ่งบางอย่างnครั้งหมายความว่ามันจะช้ากว่าnเท่าในการเรียกใช้งานเพียงครั้งเดียว
svick

3
ก่อนอื่นตัวอย่างโค้ดควรสร้างเอาต์พุตที่มีจำนวนเพิ่มมากขึ้นเนื่องจาก StopWatch ไม่เคยถูกรีเซ็ตในลูป และโดย "ควร" ฉันหมายความว่ามันทำ (ฉันตรวจสอบ) ดังนั้นผลลัพธ์ของคุณไม่ตรงกับรหัส ประการที่สองเมื่อฉันแก้ไขรหัสให้ทำ Stop / Write / Reset / Start ในลูปการวัดครั้งแรกก็เหมือนกับส่วนที่เหลือ ฉันเดาว่า DoSomething ของคุณทำอะไรบางอย่างได้นานกว่าครั้งแรกที่มันทำงาน JIT อาจจะใช่หรือไม่ใช่เหตุผลก็ได้ แต่ไม่ใช่ว่า Stopwatch ส่งผลกระทบต่อการวัด ดังนั้น -1
ILIA BROUDNO

2
ILIA BROUDNO ถูกต้องแน่นอนฉันได้ผลลัพธ์เดียวกัน @ series0ne คุณมี Console.WriteLine อยู่ภายในลูปเขียน ms จนถึงตอนนี้ เนื่องจากคุณหยุดนาฬิกาหลังจากที่วงจบมันเพิ่มขึ้นเมื่อเวลาผ่านไปในแต่ละรอบดังนั้นเราควรเห็นบางอย่างเช่น 3, 6, 10, 12, 15 ... ตามเวลาที่สะสมไว้ในการประหารชีวิต
Rui Miguel Pinheiro

29

StopWatch ชั้นมองหาทางออกที่ดีที่สุดของคุณ

Stopwatch sw = Stopwatch.StartNew();
DoSomeWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

Stopwatch.IsHighResolutionนอกจากนี้ยังมีข้อมูลคงที่เรียกว่า แน่นอนว่านี่เป็นปัญหาฮาร์ดแวร์และระบบปฏิบัติการ

บ่งชี้ว่าตัวจับเวลานั้นขึ้นอยู่กับตัวนับประสิทธิภาพความละเอียดสูงหรือไม่


18

หากคุณสนใจที่จะเข้าใจประสิทธิภาพการทำงานคำตอบที่ดีที่สุดคือการใช้ profiler

มิฉะนั้นSystem.Diagnostics.StopWatchให้ตัวจับเวลาความละเอียดสูง


ถูกต้องอย่างแน่นอน! ฉันรู้สึกท้อแท้เล็กน้อยที่มีผู้คนมากมายที่นี่แนะนำให้ใช้นาฬิกาจับเวลาเพราะมันไม่แม่นยำ อย่างไรก็ตามตามที่คุณแนะนำให้ใช้ Performance Profiler นี่เป็นวิธีที่ถูกต้องที่จะทำ! +1
Matthew Layton

7

StopWatchจะใช้ตัวนับความละเอียดสูง

นาฬิกาจับเวลาจะวัดเวลาที่ผ่านไปโดยนับการนับติ๊กในกลไกตัวจับเวลาพื้นฐาน หากฮาร์ดแวร์และระบบปฏิบัติการที่ติดตั้งรองรับตัวนับประสิทธิภาพความละเอียดสูงคลาส Stopwatch จะใช้ตัวนับนั้นเพื่อวัดเวลาที่ผ่านไป มิฉะนั้นคลาสนาฬิกาจับเวลาใช้ตัวจับเวลาระบบเพื่อวัดเวลาที่ผ่านไป ใช้ฟิลด์ความถี่และ IsHighResolution เพื่อกำหนดความแม่นยำและความละเอียดของการดำเนินการกำหนดเวลานาฬิกาจับเวลา

หากคุณวัดค่า IO ตัวเลขของคุณจะได้รับผลกระทบจากเหตุการณ์ภายนอกและฉันจะกังวลอีกมาก ความถูกต้อง (ตามที่คุณระบุไว้ข้างต้น) แต่ฉันจะใช้ช่วงของการวัดและพิจารณาค่าเฉลี่ยและการกระจายของตัวเลขเหล่านั้น


0
 using System.Diagnostics;
 class Program
 {
    static void Test1()
    {
        for (int i = 1; i <= 100; i++)
        {
            Console.WriteLine("Test1 " + i);
        }
    }
  static void Main(string[] args)
    {

        Stopwatch sw = new Stopwatch();
        sw.Start();
        Test1();
        sw.Stop();
        Console.WriteLine("Time Taken-->{0}",sw.ElapsedMilliseconds);
   }
 }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.