DateTime เป็นวิธีที่ดีที่สุดในการวัดประสิทธิภาพของฟังก์ชันหรือไม่


474

ฉันต้องการค้นหาคอขวดและต้องการเวลาการวัดที่แม่นยำที่สุดเท่าที่จะทำได้

โค้ดต่อไปนี้เป็นวิธีที่ดีที่สุดในการวัดประสิทธิภาพหรือไม่

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);

อย่างไรก็ตามถ้าคุณไม่ได้มองหาเคาน์เตอร์วัดประสิทธิภาพที่รวดเร็วและสกปรกก็สามารถใช้ได้
Jonathan C Dickinson

1
หากคุณต้องการความแม่นยำมากขึ้นให้ใช้นาฬิกาจับเวลา GetTimestamp มิฉะนั้นคำตอบก็ดี
dbasnett

@dbasnett คุณช่วยอธิบายรายละเอียดเพิ่มเติมได้ไหม?
David Basarab

ในตัวอย่างข้างต้นให้เปลี่ยนเริ่มต้นและสิ้นสุดเวลาเป็นเวลานานและกำหนด Stopwatch.GetTimestamp ให้กับพวกเขาแทน DateTime.Now เวลาที่ใช้คือ (สิ้นสุด - เริ่ม) / นาฬิกาจับเวลาความถี่
dbasnett

ดูเพิ่มเติม: The Case Against DateTime.Now
Matt Johnson-Pint

คำตอบ:


649

ไม่มันไม่ใช่. ใช้นาฬิกาจับเวลา (ในSystem.Diagnostics)

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

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

นาฬิกาจับเวลาตรวจสอบการมีอยู่ของตัวจับเวลาที่มีความแม่นยำสูงโดยอัตโนมัติ

เป็นมูลค่าการกล่าวขวัญที่DateTime.Nowมักจะค่อนข้างช้ากว่าDateTime.UtcNowเนื่องจากงานที่ต้องทำกับเขตเวลา, เวลาและอื่น ๆ

DateTime โดยปกติแล้ว NowNow จะมีความละเอียด 15 ms ดูโพสต์บล็อกของ John Chapmanเกี่ยวกับDateTime.Nowความแม่นยำเพื่อการสรุปที่ยอดเยี่ยม

เรื่องไม่สำคัญที่น่าสนใจ: นาฬิกาจับเวลาจะหยุดทำงานDateTime.UtcNowหากฮาร์ดแวร์ของคุณไม่รองรับตัวนับความถี่สูง คุณสามารถตรวจสอบเพื่อดูว่านาฬิกาจับเวลาใช้ฮาร์ดแวร์เพื่อให้บรรลุความแม่นยำสูงโดยดูที่สนามคงStopwatch.IsHighResolution


3
ฉันต้องการหนึ่ง PerformWork (); ก่อนนาฬิกาจับเวลาสำหรับ "การอุ่นเครื่อง"
DiVan

2
ต้องเพิ่มคำแนะนำว่าหากคุณPerformWork()สั้นมากคุณอาจจะเรียกมันซ้ำ ๆ และคำนวณค่าเฉลี่ยของจำนวนการโทร นอกจากนี้ให้เวลาโทรทั้งชุดแทนที่จะเริ่ม / หยุดStopwatchเพื่อหลีกเลี่ยงผลกระทบจากไฟแฟลชที่จะทำให้การวัดเวลาของคุณยุ่งเหยิง
devgeezer

1
นาฬิกาจับเวลาไม่ได้เป็นเธรดที่ปลอดภัยสำหรับมัลติคอร์ ดูstackoverflow.com/questions/6664538/…และstackoverflow.com/questions/1149485/…
Pavel Savara

1
sw.ElapsedMilliseconds; ยังสามารถ
ห้อย

2
@Pavel เพื่อให้มีความชัดเจน Microsoft ขอแนะนำนาฬิกาจับเวลาเป็นโซลูชันที่ดีที่สุด (ค่าใช้จ่ายต่ำและมีความแม่นยำสูง) ในตัวประมวลผลมัลติคอร์ที่ทันสมัยซึ่งใช้ Windows 7 และ Windows 8 msdn.microsoft.com/en-us/library/windows/ เดสก์ท็อป / …
Ron

91

หากคุณต้องการสิ่งที่รวดเร็วและสกปรกฉันขอแนะนำให้ใช้ Stopwatch แทนเพื่อความแม่นยำในระดับที่สูงขึ้น

Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();

Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);

อีกทางเลือกหนึ่งถ้าคุณต้องการบางสิ่งที่ซับซ้อนกว่านี้เล็กน้อยคุณควรพิจารณาใช้โปรแกรมสร้างโปรไฟล์ภายนอกเช่นANTS


56

บทความนี้กล่าวว่าเป็นครั้งแรกของทั้งหมดที่คุณต้องการเปรียบเทียบสามทางเลือกStopwatch, และDateTime.NowDateTime.UtcNow

นอกจากนี้ยังแสดงให้เห็นว่าในบางกรณี (เมื่อไม่มีตัวนับประสิทธิภาพ) นาฬิกาจับเวลากำลังใช้ DateTime.UtcNow + การประมวลผลพิเศษบางอย่าง เพราะเห็นได้ชัดว่าในกรณีนั้น DateTime.UtcNow เป็นตัวเลือกที่ดีที่สุด (เพราะคนอื่นใช้ + ประมวลผลบางส่วน)

อย่างไรก็ตามตามที่ปรากฎตัวนับมีอยู่เกือบทุกตัว - ดูคำอธิบายเกี่ยวกับตัวนับประสิทธิภาพความละเอียดสูงและการมีอยู่ที่เกี่ยวข้องกับ. NET Stopwatch? .

นี่คือกราฟประสิทธิภาพ ขอให้สังเกตว่า UtcNow มีประสิทธิภาพราคาต่ำเมื่อเปรียบเทียบกับทางเลือก

ป้อนคำอธิบายภาพที่นี่

แกน X คือขนาดข้อมูลตัวอย่างและแกน Y เป็นเวลาสัมพัทธ์ของตัวอย่าง

สิ่งหนึ่งที่Stopwatchดีกว่าคือมันให้การวัดเวลาความละเอียดสูงกว่า อีกประการหนึ่งคือธรรมชาติของ OO มากขึ้น อย่างไรก็ตามการสร้างตัวคลุม OO UtcNowไม่สามารถทำได้ยาก


ลิงค์แรกดูเหมือนจะเสียหาย
Peter Mortensen

1
กลายเป็นว่าหัก .. ไทม์แมชชีนสามารถแสดงให้ฉันเห็นฉันเดา Btw ทำไมคุณถึงแก้ไข "สาม" ฉันไม่ต้องการที่นี่
Valentin Kuzub

18

มีประโยชน์ในการส่งรหัสการเปรียบเทียบของคุณไปยังคลาส / วิธีการยูทิลิตี้ StopWatchชั้นไม่จำเป็นต้องมีDisposedหรือStoppedข้อผิดพลาด ดังนั้นรหัสที่ง่ายที่สุดในบางครั้งการกระทำคือ

public partial class With
{
    public static long Benchmark(Action action)
    {
        var stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
}

ตัวอย่างรหัสโทร

public void Execute(Action action)
{
    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in {0} ms.”, time);
}

นี่คือเวอร์ชันวิธีการขยาย

public static class Extensions
{
    public static long Benchmark(this Action action)
    {
        return With.Benchmark(action);
    }
}

และตัวอย่างรหัสการโทร

public void Execute(Action action)
{
    var time = action.Benchmark()
    log.DebugFormat(“Did action in {0} ms.”, time);
}

1
สิ่งที่เกี่ยวกับความละเอียดที่ดีกว่า หลายสิ่งเกิดขึ้นในเวลาน้อยกว่าหนึ่งมิลลิวินาที
Henrik

ส่งคืนคุณสมบัติที่ผ่านไปแล้วจึงเป็น TimeSpan ฉันแค่แสดงให้คุณเห็นรูปแบบ ขอให้สนุกกับการนำไปใช้งาน
Anthony Mastrean

กลับมาElapsed.TotalMillisecondsเพื่อความแม่นยำที่สูงขึ้น ดูคำถามนี้ด้วยเช่นกันstackoverflow.com/questions/8894425/…
nawfal

16

นาฬิกาจับเวลาการทำงานจะดีกว่า (ความแม่นยำสูงกว่า) ฉันขอแนะนำให้ดาวน์โหลดเพียงหนึ่งในโปรไฟล์ที่ได้รับความนิยมด้วย ( DotTraceและANTSเป็นสิ่งที่ฉันใช้มากที่สุด ... การทดลองใช้ฟรีสำหรับ DotTrace นั้นทำงานได้อย่างสมบูรณ์และไม่ชอบคนอื่น ๆ )


13

ใช้คลาส System.Diagnostics.Stopwatch

Stopwatch sw = new Stopwatch();
sw.Start();

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.

11

Ditto Stopwatch นั้นดีกว่า

คุณควรตรวจสอบว่า "// กระบวนการดำเนินการบางอย่าง" ของคุณเป็นกระบวนการที่สั้นมากหรือไม่

โปรดจำไว้ว่าการรันครั้งแรกของ "// กระบวนการดำเนินการบางอย่าง" ของคุณอาจช้ากว่าการเรียกใช้ครั้งต่อไป

ฉันมักจะทดสอบวิธีการโดยใช้มัน 1,000 ครั้งหรือ 1000000 ครั้งในวงและฉันได้รับข้อมูลที่ถูกต้องมากขึ้นกว่าการทำงานเพียงครั้งเดียว


9

ทั้งหมดนี้เป็นวิธีที่ยอดเยี่ยมในการวัดเวลา แต่นั่นเป็นเพียงวิธีการทางอ้อมในการค้นหาคอขวด

วิธีที่ตรงที่สุดในการค้นหาคอขวดในเธรดคือการทำให้มันทำงานและในขณะที่มันกำลังทำอะไรก็ตามที่ทำให้คุณรอให้หยุดด้วยการหยุดชั่วคราวหรือกุญแจแตก ทำเช่นนี้หลายครั้ง หากคอขวดของคุณใช้เวลา X% ของเวลา X% คือความน่าจะเป็นที่คุณจะจับมันในการกระทำในแต่ละภาพรวม

ต่อไปนี้เป็นคำอธิบายที่สมบูรณ์มากขึ้นเกี่ยวกับวิธีการและสาเหตุของการทำงาน


7

@ Sean Chambers

FYI, คลาส. NET Timer ไม่ได้มีไว้สำหรับการวินิจฉัย แต่จะสร้างเหตุการณ์ในช่วงเวลาที่กำหนดไว้ล่วงหน้าเช่นนี้ (จากMSDN ):

System.Timers.Timer aTimer;
public static void Main()
{
    // Create a timer with a ten second interval.
    aTimer = new System.Timers.Timer(10000);

    // Hook up the Elapsed event for the timer.
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    // Set the Interval to 2 seconds (2000 milliseconds).
    aTimer.Interval = 2000;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program.");
    Console.ReadLine();
}

// Specify what you want to happen when the Elapsed event is 
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}

ดังนั้นนี่จึงไม่ช่วยให้คุณรู้ว่าต้องใช้เวลานานแค่ไหนในการผ่านไประยะหนึ่ง

ตัวจับเวลาถูกเปิดเผยเป็นตัวควบคุมใน System.Windows.Forms ... คุณสามารถค้นหาได้ในกล่องเครื่องมือออกแบบของคุณใน VS05 / VS08


6

นี่เป็นวิธีที่ถูกต้อง:

using System;
using System.Diagnostics;

class Program
{
    public static void Main()
    {
        Stopwatch stopWatch = Stopwatch.StartNew();

            // some other code

        stopWatch.Stop();

        // this not correct to get full timer resolution
        Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds);

        // Correct way to get accurate high precision timing
        Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds);
    }
}

สำหรับข้อมูลเพิ่มเติมไปผ่านการใช้นาฬิกาจับเวลาแทน DataTime สำหรับการนับประสิทธิภาพการทำงานที่ถูกต้อง


6

Visual Studio Team Systemมีคุณสมบัติบางอย่างที่อาจช่วยแก้ไขปัญหานี้ โดยพื้นฐานแล้วคุณสามารถเขียนการทดสอบหน่วยและผสมในสถานการณ์ที่แตกต่างกันเพื่อทำงานกับซอฟต์แวร์ของคุณซึ่งเป็นส่วนหนึ่งของความเครียดหรือการทดสอบโหลด นี่อาจช่วยระบุส่วนของรหัสที่ส่งผลต่อประสิทธิภาพการใช้งานของคุณมากที่สุด

ไมโครซอฟท์' รูปแบบและวิธีปฏิบัติในกลุ่มที่มีคำแนะนำบางอย่างในระบบ Visual Studio Team ผลการดำเนินงานแนะแนวการทดสอบ


5

ฉันเพิ่งพบโพสต์ในบล็อกของ Vance Morrison เกี่ยวกับคลาส CodeTimer ที่เขาเขียนซึ่งทำให้ใช้งานStopWatchได้ง่ายขึ้นและทำสิ่งที่เรียบร้อยอยู่ด้านข้าง


5

นี่ไม่ใช่มืออาชีพมากพอ:

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

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

รุ่นที่เชื่อถือได้มากขึ้นคือ:

PerformWork();

int repeat = 1000;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
   PerformWork();
}

sw.Stop();

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

ในรหัสจริงของฉันฉันจะเพิ่มการเรียก GC.Collect เพื่อเปลี่ยน heap ที่ถูกจัดการเป็นสถานะที่รู้จักและเพิ่มการโทรแบบ Sleep เพื่อให้สามารถแยกช่วงของรหัสที่แตกต่างกันได้อย่างง่ายดายในโปรไฟล์ ETW


4

ฉันได้ทำการตรวจสอบประสิทธิภาพน้อยมาก (ฉันมักจะคิดว่า "นี่ช้าทำให้เร็วขึ้น") ดังนั้นฉันจึงไปกับเรื่องนี้

google เปิดเผยแหล่งข้อมูล / บทความจำนวนมากสำหรับการตรวจสอบประสิทธิภาพ

หลายคนพูดถึงการใช้ pinvoke เพื่อรับข้อมูลประสิทธิภาพ วัสดุจำนวนมากที่ฉันศึกษาเท่านั้นพูดถึงการใช้ perfmon ..

แก้ไข:

เห็นการพูดถึง StopWatch แล้ว .. Nice! ฉันได้เรียนรู้บางสิ่งบางอย่าง :)

ดูเหมือนบทความที่ดี


4

วิธีที่ฉันใช้ภายในโปรแกรมของฉันคือการใช้คลาส StopWatch ดังที่แสดงไว้ที่นี่

Stopwatch sw = new Stopwatch();
sw.Start();


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.