.NET的開發效能提示中,有一條原則是"不要把try...catch當成正常流程"。今天在修改前人程式時,看到一個挺經典的真實案例,跟大家分享一下。

排版顯示純文字
   1:  static void avoidTryCatchDemo(string file)
   2:  {
   3:      StreamReader sr = 
   4:          new StreamReader(file);
   5:      System.Diagnostics.Stopwatch sw = 
   6:          new System.Diagnostics.Stopwatch();
   7:      sw.Start();
   8:      string line = "";
   9:      while ((line = sr.ReadLine()) != null)
  10:      {
  11:          string[] p = line.Split(';');
  12:          //...略...
  13:          try
  14:          {
  15:              dt = (MyNamespace.DataType)Enum.Parse(
  16:                  typeof(MyNamespace.DataType),
  17:                  p[4]);
  18:          }
  19:          catch
  20:          {
  21:          }
  22:          //...略...
  23:      }
  24:      sw.Stop();
  25:      sr.Close();
  26:      Console.WriteLine(
  27:          string.Format("Load {0} in {1:#,##0}ms", 
  28:          file, sw.ElapsedMilliseconds)
  29:          );
  30:  }

我先是發現程式每次啟動的時間都長達數十秒到一分鐘,忍耐了一陣子,最近終於有空檔,就鑽進去看個究竟,找看看有無可調整之處。我抓這個問題的做法是在用VS 2005的Debug模式啟動程式,在啟動等待期間幾次按下中斷,統計一下程式都停在哪裡,應該就是主要耗時的地方。試了幾次,程式都停在第15列,仔細一看,唷! try...catch,該不會是這裡造成效能狂降? 於是我將Code改成:

排版顯示純文字
        try
        {
            dt = (MyNamespace.DataType)Enum.Parse(
                typeof(MyNamespace.DollarType),
                p[4]);
        }
        catch
        {
            Console.WriteLine("Damn! I's wasting time!");
        }

理論上,只要進入catch block,就意味著已經付出昂貴的效能代價。我還加上了Stopwatch(先前有介紹過)來計算耗用時間,切記,建立衡量基準是所有效能調校工作的第一步,也是要享受成就感不可或缺的關鍵步驟。

先跑了一次,Wow... Console印出一大堆程式為了浪費時間的懺悔,然後計時數據是

Load FileSYS in 79ms
Load FileE in 14,766ms
Load FileA in 2,907ms
Load FileB in 1,609ms
Load FileC in 2,708ms
Load FileD in 3,121ms

進一步追查,因為資料不嚴謹,有很多p[4]是空字串而轉換失敗。依照效能法則,我應該要避開可預防的Exception,於是把程式改成:

排版顯示純文字
        try
        {
            if (p[4].Length>0)
                dt = (MyNamespace.DataType)Enum.Parse(
                typeof(MyNamespace.DollarType),
                p[4]);
        }
        catch
        {
            Console.WriteLine("Damn! I's wasting time!");
        }

再跑一次,改過之後的效能數字:

Load FileSYS in 74ms
Load FileE in 5,514ms
Load FileA in 22ms
Load FileB in 12ms
Load FileC in 23ms
Load FileD in 25ms

不多不多,不過差了100倍而已!

由以上的實例,提醒大家,不要把try...catch視為合理的流程,每次進入catch Block都要想成我們是在打破玻璃,拉下拉捍讓疾駛中的捷運電車停下來,沒事亂拉一通,就等著接罰單吧!


Comments

Be the first to post a comment

Post a comment