【所見即所得】Try Catch 效率問題


 

 

 

一、問題引入 

     維護老項目,看到下面一個函數:

    /// <summary>
    /// 從ViewState中獲取某個屬性的值。如果該屬性不存在,返回空字符串。

    /// </summary>
    /// <param name="PropertyName">屬性名稱</param>
    /// <returns>屬性值(屬性不存在時返回空字符串)</returns>
    protected string GetViewState(string PropertyName)
    {
        try
        {
            return ViewState[PropertyName].ToString();
        }
        catch (NullReferenceException)
        {
            return "";
        }
    }

二、問題分析

     代碼功能很明顯“從ViewState中獲取某個屬性的值。如果該屬性不存在,返回空字符串。”。看起來也很整潔,想起以前在園子類看到的討論try-catch的性能問題,基本上已經有定論。自己想驗證下:

    測試的類代碼如下:

 public  class TryCatch {
      static Stopwatch sw = new Stopwatch();
       /// <summary>
       /// 帶有finally的try引發異常來完成字符串賦值
       /// </summary>
       /// <param name="str">傳入參數,調用的時候會是null</param>
       /// <returns></returns>
      public static string TryCatchwithFinally(string str) {
          sw.Reset();
          sw.Start();
          try {
              return str.ToString();
          }
          catch (NullReferenceException) {
              return "exception!";
          }
          finally {
              sw.Stop();
              Console.WriteLine("發生exception,帶finally的trycatch用時{0}毫秒",sw.ElapsedMilliseconds);
          }
      }
      /// <summary>
      /// 帶有finally的try不引發異常通過ifelse來完成字符串賦值
      /// </summary>
      /// <param name="str">傳入參數,調用的時候會是null</param>
      /// <returns></returns>
      public static string IfElsewithFinally(string str) {
          sw.Reset();
          sw.Start();
          try {
              if (!string.IsNullOrEmpty(str)) {
                  return str.ToString();
              }
              else {
                  return "";
              }

          }
          catch (NullReferenceException) {
              return "exception!";
          }
          finally {
              sw.Stop();
              Console.WriteLine("不發生exception,帶finally得ifelse用時{0}毫秒", sw.ElapsedMilliseconds);
          }
      }
      /// <summary>
      ///  不帶有finally的try不引發異常通過ifelse來完成字符串賦值
      /// </summary>
      /// <param name="str">傳入參數,調用的時候會是null</param>
      /// <returns></returns>
      public static string IfElse(string str) {
          sw.Reset();
          sw.Start();
          try {
              if (!string.IsNullOrEmpty(str)) {
                  return str.ToString();
              }
              else {
                  sw.Stop();
                  Console.WriteLine("發生exception,ifelse用時{0}毫秒", sw.ElapsedMilliseconds);
                  return "";
              }
          }
          catch (NullReferenceException) {
             
              return "exception!";
        
          }
        
      }
      /// <summary>
      /// 不帶有finally的try引發異常來完成字符串賦值
      /// </summary>
      /// <param name="str">傳入參數,調用的時候會是null</param>
      /// <returns></returns>
      public static string Trycatch(string str) {
          sw.Reset();
          sw.Start();
          try {
              return str.ToString();
          }
          catch (NullReferenceException) {
              sw.Stop();
              Console.WriteLine("發生exception,trycatch用時{0}毫秒", sw.ElapsedMilliseconds);
              return "exception!";
             
          }

      }
    }

主調函數如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FMS_Refacting.try_catch;


namespace Fibo.ConsoleApplication {
        class Program {
            static void Main(string[] args) {

                TryCatch.IfElsewithFinally(null);//1
                TryCatch.Trycatch(null);//2
                TryCatch.TryCatchwithFinally(null);//3               
                TryCatch.IfElse(null);//3
                Console.ReadKey();

            }
        
    }
   
}

 

   結果如下:

image

 

  將主調函數main中4個語句調換順序,得到的測試結果大體相同。也就是,用trycatch實現邏輯(簡單的)耗時在100毫秒(這個有可能不太准確,不過大約在100倍左右)以上,而ifelse基本不耗時。同一類型的異常被第一次拋出的時候性能會下降很多,而在后續拋出則基本沒有影響,CLR在異常處理的這一點進行了強大的優化。

  同時finally中如果沒有什么復雜的邏輯的話並不會影響性能。

  下面是 imfunny兄一些高見:

這個結論貌似不對的。
和復雜的邏輯其實沒有什么關系。所以樓主改正下呢。
缺少了finally 實際上就缺少了ret的分界表,於是就導致了對異常類型以及異常類型的匹配過程。而這個部分才是耗時的。
 

 

finally 即使有復雜的邏輯也沒有關系。這個其實是代碼執行的時間。比如有些對資源進行回收導致的代的回收等。
實際上catch過程可用可不用。如果不用可以再Application撲捉到嘿嘿。

  當然為了美觀和可讀性,ifelse可以用?:和??來代替。

 

三、所得

    對trycatch的運用;只控制異常,不控制邏輯。

    堅信:過度的設計是犯罪,不設計更是犯罪!

    知道了,並運用了Stopwatch類;

   以后繼續所見即所得的學習!

 

PS:  在園子里面找到了金大俠的大作:深入理解CLR異常處理機制(http://www.cnblogs.com/bitfan/archive/2009/12/03/1616550.html)。從原理上講的已經很透徹了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM