今天跟網友討論程式效能時,注意到在使用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);

    }

運行結果如下

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

    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);

    }

運行結果如下

    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);
    }

運行結果如下

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

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