[C#]用Stopwatch計算累計耗費時間的注意事項

今天跟網友討論程式效能時,注意到在使用Stopwatch的一些注意事項,簡單紀錄一下。

Stopwatch類別重要的成員不外乎StartNew、Start、Stop、Reset、ElapsedTicks、與ElapsedMilliseconds。使用上,只要依序呼叫Start→Stop→ElapsedMilliseconds或ElapsedTicks,就可以得到運行的耗費時間。要計算多段程式累計耗費的時間,也只要Start→Stop→…→Start→Stop→ElapsedMilliseconds或ElapsedTicks即可。

但在計算累計耗費時間時,也有人會用Reset→Start→Stop→加總→…這樣的方法來做。但這樣的做法會比較耗時,求得的值也會有誤差。

讓我們來先看段程式

        static void Main(string[] args)
{
int count = 1000000;
long total = 0;
Stopwatch sw = new Stopwatch();

for (int i = 1; i <= count; i++)
{
sw.Reset();
sw.Start();
string guid = Guid.NewGuid().ToString();
sw.Stop();
total += sw.ElapsedMilliseconds;
}
Console.WriteLine(total);

sw.Reset();
for (int i = 1; i <= count; i++)
{
sw.Start();
string guid = Guid.NewGuid().ToString();
sw.Stop();
}
Console.WriteLine(sw.ElapsedMilliseconds);

}


運行結果如下

image

從這運行結果我們可以看出,兩種不同作法的結果差異很大。那哪個才是正確的呢?讓我們再看些例子。

        static void Main(string[] args)
{
int count = 1000;
long total = 0;
Stopwatch sw = new Stopwatch();

for (int i = 1; i <= count; i++)
{
sw.Reset();
sw.Start();
System.Threading.Thread.Sleep(10);
sw.Stop();
total += sw.ElapsedMilliseconds;
}
Console.WriteLine(total);

sw.Reset();
for (int i = 1; i <= count; i++)
{
sw.Start();
System.Threading.Thread.Sleep(10);
sw.Stop();
}
Console.WriteLine(sw.ElapsedMilliseconds);

}



運行結果如下

image

        static void Main(string[] args)
{
int count = 10;
long total = 0;
Stopwatch sw = new Stopwatch();

for (int i = 1; i <= count; i++)
{
sw.Reset();
sw.Start();
System.Threading.Thread.Sleep(1000);
sw.Stop();
total += sw.ElapsedMilliseconds;
}
Console.WriteLine(total);

sw.Reset();
for (int i = 1; i <= count; i++)
{
sw.Start();
System.Threading.Thread.Sleep(1000);
sw.Stop();
}
Console.WriteLine(sw.ElapsedMilliseconds);
}

運行結果如下

image









由上實驗可以看出,當運算量龐大時,兩個方法所求得的值會變得相近,因此很明顯的可以看出,自行加總的方法是有誤差的。

之所以會有這樣的現象,個人推測是由於小於毫秒的花費時間,在使用加總的方式處理時,會被忽略不記所導致。