2010-10-11 357 views
36

我想測量一段代碼的執行情況,我想知道做到這一點的最佳方法是什麼?使用C#測量執行時間

選項1:

DateTime StartTime = DateTime.Now; 

//Code 

TimeSpan ts = DateTime.Now.Subtract(StartTime); 
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
     ts.Hours, ts.Minutes, ts.Seconds, 
     ts.Milliseconds/10); 
Console.WriteLine(elapsedTime, "RunTime"); 

選項2: 使用System.Diagnostics程序;

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

    //Code 

    stopWatch.Stop(); 
    // Get the elapsed time as a TimeSpan value. 
    TimeSpan ts = stopWatch.Elapsed; 

    // Format and display the TimeSpan value. 
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
     ts.Hours, ts.Minutes, ts.Seconds, 
     ts.Milliseconds/10); 
    Console.WriteLine(elapsedTime, "RunTime"); 

這不僅僅是基準測試,它實際上是應用程序的一部分。函數執行的時間是相關數據。它不需要是原子或超精確的。

哪個選項更適合生產代碼,還是其他人使用不同的或者更好的東西?

+0

問得好!我很好奇答案! – 2010-10-11 02:43:33

回答

28

Stopwatch類是專門設計用來測量經過時間,並可能(如果適用於您的硬件)使用底層高頻硬件定時器提供了良好的粒度/精度。所以這似乎是最好的選擇。

IsHighResolution property可用於確定高分辨率定時是否可用。每文檔,這個類提供的「最好的」的Win32 API的精確定時的包裝:

具體來說,Frequency場和 GetTimestamp方法可以在 地方的非託管的Win32 API QueryPerformanceFrequency和使用 QueryPerformanceCounter

這些Win32 API [此處]和鏈接的MSDN文檔2上有詳細的背景信息。

高分辨率計時器

計數器是在 編程中用於指一個 遞增變量的通用術語。一些系統 包括高分辨率性能 計數器,其提供高分辨率 經過的時間。

如果系統中存在一個高分辨率的性能計數器 ,你可以 使用QueryPerformanceFrequency的 功能表達的頻率,以每秒 計數。計數值 取決於處理器。例如,在某些 處理器上,計數 可能是處理器時鐘的週期速率。

QueryPerformanceCounter的功能 檢索 高分辨率性能計數器的當前值。 通過在 代碼段的 部分的 的起始和結尾調用此函數,應用程序本質上使用 計數器作爲高分辨率 計時器。例如,假設 QueryPerformanceFrequency指示 高分辨率性能計數器的頻率爲 每秒50,000個計數。如果 應用程序調用 QueryPerformanceCounter的立即 之前,立即進行定時的代碼 節過後, 計數器值可能分別爲1500個計數 和3500計數。這些 值將指示執行代碼 時已經過去.04秒 (2000個計數)。

+0

'Stopwatch'也使用高分辨率定時器(當它可用時),這在測量代碼時很重要執行時間短。 – Justin 2010-10-11 03:14:57

+0

@Kragen - 這就是我對底層定時器的意思。我將通過參考Win32 API進行闡述。 – 2010-10-11 12:42:25

+0

請注意,它是'Stopwatch'而不是'StopWatch'(次要的,我知道,但是如果你弄錯了,autoresolving依賴關係將不起作用)。 – 2013-05-14 07:45:34

5

既不會影響性能,因爲你說它不那麼重要。秒錶似乎更合適 - 你只是減去時間而不是另一個日期。日期的東西需要更多的內存和CPU時間來處理。還有一些方法可以使代碼更清潔,以防計劃在多個地方重複使用代碼。想起超載using。我會尋找一個例子。

http://stevesmithblog.com/blog/great-uses-of-using-statement-in-c/

public class ConsoleAutoStopWatch : IDisposable 
{ 
    private readonly Stopwatch _stopWatch; 

    public ConsoleAutoStopWatch() 
    { 
     _stopWatch = new Stopwatch(); 
     _stopWatch.Start(); 
    } 

    public void Dispose() 
    { 
     _stopWatch.Stop(); 
     TimeSpan ts = _stopWatch.Elapsed; 

     string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
              ts.Hours, ts.Minutes, ts.Seconds, 
              ts.Milliseconds/10); 
     Console.WriteLine(elapsedTime, "RunTime"); 
    } 
} 

private static void UsingStopWatchUsage() 
{ 
    Console.WriteLine("ConsoleAutoStopWatch Used: "); 
    using (new ConsoleAutoStopWatch()) 
    { 
     Thread.Sleep(3000); 
    } 
} 
+0

我不認爲需要更多時間。我認爲它不太準確,因爲它不是用於這種測量。 – codekaizen 2010-10-11 02:48:46

6

我一般用StopWatch對於這種情況:好了,從偷來的代碼。

MSDN頁:

秒錶

提供一組,你可以用它來 準確地測量經過時間的方法和 屬性。

在以下文章中,我使用LINQ的執行時間比較VS PLINQ:

Parallel LINQ (PLINQ) with Visual Studio 2010

+0

+1鏈接到MSDN,我發現它看起來名稱已經從'StopWatch'變更爲'秒錶' – 2012-05-31 17:52:28

1

兩者都可能適合您的需求就好了,但我會說使用StopWatch。爲什麼?因爲它意味着你正在做的任務。

你已經有了一個能夠返回當前日期/時間的類,它可以用於計時,並且你有一個專門用於計時的類。

在這種情況下,如果你需要毫秒精度(在這種情況下,StopWatch更準確)的區別只是是否真的存在,但如果一個工具,專門存在一般主要的任務你正在尋找那麼它的最好的一個使用。

13

這不僅僅是因爲StopWatch更準確,而且DateTime.Now在某些情況下會給出不正確的結果。

考慮在夏令時會發生什麼情況切換過來,例如—使用DateTime.Now實際上可以給答案!

1

我有一個專門做這種事情的小班。它使用秒錶類 - c# micro perfomance testing

例如。

var tester = new PerformanceTester(() => SomeMethod()); 
tester.MeasureExecTime(1000); 
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds)); 
0

使用下面的代碼

DateTime dExecutionTime; 
dExecutionTime = DateTime.Now; 
     TimeSpan span = DateTime.Now.Subtract(dExecutionTime); 
        lblExecutinTime.Text = "total time taken " + Math.Round(span.TotalMinutes,2) + " minutes . >>---> " + DateTime.Now.ToShortTimeString(); 
0

我把麥的答案簡化它,並使它更一般的情況下,有些則需要登錄到別的地方:

public class AutoStopWatch : Stopwatch, IDisposable { 

    public AutoStopWatch() { 
     Start(); 
    } 

    public virtual void Dispose() { 
     Stop(); 
    } 
} 

public class AutoStopWatchConsole : AutoStopWatch { 

    private readonly string prefix; 

    public AutoStopWatchConsole(string prefix = "") { 
     this.prefix = prefix; 
    } 

    public override void Dispose() { 
     base.Dispose(); 

     string format = Elapsed.Days > 0 ? "{0} days " : ""; 
     format += "{1:00}:{2:00}:{3:00}.{4:00}"; 

     Console.WriteLine(prefix + " " + format.Format(Elapsed.Days, Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds, Elapsed.Milliseconds/10)); 
    } 
} 

private static void Usage() { 

    Console.WriteLine("AutoStopWatch Used: "); 
    using (var sw = new AutoStopWatch()) { 
     Thread.Sleep(3000); 

     Console.WriteLine(sw.Elapsed.ToString("h'h 'm'm 's's'")); 
    } 

    Console.WriteLine("AutoStopWatchConsole Used: "); 
    using (var sw = new AutoStopWatchConsole()) { 
     Thread.Sleep(3000); 
    } 

}