[C#][Tips]迴圈中別建立執行個體

今天處理一個小問題,朋友詢問如何加快開啟程式時間

當下很直覺的回答:別再Form_Load處理太複雜或耗時作業

但後來看code發現Form_Load邏輯雖然不會很複雜

但因為在迴圈中包了try catch和建立執行個體(多CPU也不是這樣操的XD)

導致再開啟應用程式特別緩慢,這裡簡單測試該狀況。

行為:執行50萬次後取得結果。

 

寫法一:迴圈中包含try catch和建立執行個體

 Int32 myvalue = 0;
            Stopwatch sw = new Stopwatch();
            sw.Reset();
            sw.Start();           
            for (Int32 i = 0; i < 500000; i++)
            {
                try
                { 
                  Random rnd = new Random();//建立執行個體
                  myvalue = rnd.Next(1,999);    
                  //if.... throw new Exception            
                }
                catch(Exception ex)
                {
                
                }              
            }
            sw.Stop();
            Console.Write(myvalue + " 寫法一花費時間:" + sw.ElapsedMilliseconds.ToString() + "\r\n");

寫法二:將try catch和建立執行個體拉到迴圈外

  Random rnd1 = new Random();//建立執行個體
            myvalue = 0;
            sw.Reset();
            sw.Start();
            try
            {
                for (Int32 i = 0; i < 500000; i++)
                {
                    myvalue = rnd1.Next(1, 999); 
                     //if.... throw new Exception                  
                }
                sw.Stop();
            }
            catch (Exception ex)
            {
            
            }    
            Console.Write(myvalue + " 寫法二花費時間:" + sw.ElapsedMilliseconds.ToString() + "\r\n");

寫法三:和寫法一差不多,只差先將物件拉出迴圈外並宣告null

  Random rnd2=null;//宣告null
            myvalue = 0;
            sw.Reset();
            sw.Start();
            for (Int32 i = 0; i < 500000; i++)
            {
                try
                {
                    rnd2 = new Random();//建立執行個體
                    myvalue = rnd2.Next(1, 999);
                    //if.... throw new Exception
                }
                catch (Exception ex)
                {
                  
                }
            }
            sw.Stop();
            Console.Write(myvalue + " 寫法三花費時間:" + sw.ElapsedMilliseconds.ToString() + "\r\n");

 

第一次

image

第二次

image

第三次

image

第四次

image

第五次

image

測試五次平均花費時間

寫法一平均時間寫法二平均時間寫法三平均時間
5071.446.85113

期望自己每天都有進步!

PS.引用文章請勿整篇複製,並請標示出該文章出處網址,感恩啦。


 

16 Comments 文章分類 [ C# ] DotBlogs Tags: C# WinForm 閱讀數 : 1715 訂閱
 

回覆

# re: [C#][Tips]迴圈中別建立執行個體
Hi,感覺寫法二的效果跟另外兩個寫法有異,寫法二是ㄧ個例外後就跳出不會繼續跑迴圈,另外兩個寫法是例外了還會繼續跑迴圈、繼續測試。而你的程式中可能有例外發生,導致寫法二只跑了幾次,所以才會造成寫法二比較快的現象。
Left by larrynung 回覆 on 2009/12/17 下午 10:59
# re: [C#][Tips]迴圈中別建立執行個體
寫法二與其餘二者的意義不太相同,迴圈中只要一出錯就結束不再跑下去,而一、三會乖乖跑足50萬次,應該是時間差這麼多的由來。以上淺見。
Left by Darkthread 回覆 on 2009/12/17 下午 11:07
# re: [C#][Tips]迴圈中別建立執行個體

和兩位大大說明一下

小弟在測試過程中,三個寫法均將Exception註解掉

所以這三個寫法都算跑足50萬次,而寫法二會有那麼大的差距

小弟認為應該是try catch和建立執行個體都拉出迴圈的影響  ^^

Left by ricochen 回覆 on 2009/12/17 下午 11:32
# re: [C#][Tips]迴圈中別建立執行個體
Hi,如果例外不會發生,那就是問題是只有方法二在迴圈內不用建立Random物件,建議可以試著把測試條件設為一樣再試試。
Left by larrynung 回覆 on 2009/12/17 下午 11:44
# re: [C#][Tips]迴圈中別建立執行個體

to larrynung :
這篇小弟主要就是說明別再迴圈內建立執行個體,而大蓋寫出三種方法來驗證小弟假設是正確的,如同方法一和三均在迴圈內建立執行個體後,效果奇差無比。^^

Left by ricochen 回覆 on 2009/12/17 下午 11:49
# re: [C#][Tips]迴圈中別建立執行個體
也是~條件一樣這篇就不用比了orz...腦帶錯亂~Sorry,++i有沒有試試看?
Left by larrynung 回覆 on 2009/12/18 上午 12:00
# re: [C#][Tips]迴圈中別建立執行個體

to larrynung :
剛剛測試++i,寫法二依然省時,而一和三同樣奇差無比。^^

Left by ricochen 回覆 on 2009/12/18 上午 12:23
# re: [C#][Tips]迴圈中別建立執行個體

這實驗滿有趣的, 值得鼓勵

Left by billchung 回覆 on 2009/12/18 上午 01:20
# re: [C#][Tips]迴圈中別建立執行個體

to billchung :
還以為bill叔要來開導小弟->論壇簽名檔<-。^^

Left by ricochen 回覆 on 2009/12/18 上午 07:14
# re: [C#][Tips]迴圈中別建立執行個體

這個應該沒問題,之前我也有測過...

題外話,之前我還看過初始化物件時,因為該物件需要去資料庫取得設定,因此每new一個就要撈一次資料,效能奇慘無比...

Left by jimmyyu 回覆 on 2009/12/18 上午 09:07
# re: [C#][Tips]迴圈中別建立執行個體

to jimmyyu :

呵呵,這也是為啥會勸誡小朋友們,loop裡可以不做複雜的事,就不要做複雜的事。

尤其是在裡面透過控制項來暫存資料,這是超常看到的問題。

例如loop裡面寫著:textbox.text+=i.toString();

Left by 91 回覆 on 2009/12/18 上午 10:19
# re: [C#][Tips]迴圈中別建立執行個體

這種實驗性的文我覺得挺有意義的, 比起貼了一堆Code在Blog, 然後又不解釋為什麼 (甚至是不知道) 要這樣寫的文好很多.

Left by billchung 回覆 on 2009/12/18 下午 12:06
# re: [C#][Tips]迴圈中別建立執行個體
我也曾經這樣試過
跟你的結果是一樣的
而且...還一模一樣的方法
真是有默契(哈哈)
Left by sam319 回覆 on 2009/12/18 下午 12:17
# re: [C#][Tips]迴圈中別建立執行個體
我好像還是沒有很懂。有一點再確認一下,方法一、三的處理規則是50萬次的迴圈不管出錯與否都要執行一次,方法二是50萬次迴圈一旦出錯就沒有必要浪費時間執行剩下沒做的次數,速度的差異應該來自於此。如果想看的是在Loop建Instance造成的影響,我建議加入第四組測試,修改方法二,把Instance建立邏輯於入Loop,再比較方法二與方法四的時間,讓"變因只有一個"(Instance在Loop外 vs Instance在Loop內),產生的差異較可以推論是Instance建立位置所造成的,我想應不致這麼懸殊。
Left by Darkthread 回覆 on 2009/12/20 上午 08:18
# re: [C#][Tips]迴圈中別建立執行個體

to Darkthread :
黑暗大,測試中其實不會有任何Exception(我先處理掉了),而try-catch在loop中,小弟認為也會有所影響,故請黑暗大只單看方法一和方法二,這樣就如黑暗大所說變因只有一個(Instance在loop外 vs Instance在loop內),或許把try-catch拿掉,測試主題應該更明顯,順便附上檔案。^^

http://homepage8.seed.net.tw/web@1/rico/mytest.rar

 

Left by ricochen 回覆 on 2009/12/20 上午 11:26
# re: [C#][Tips]迴圈中別建立執行個體
to RiCo, 這樣說明我就了解了,原來throw exception可以不納入考慮(原本以為是省略部分程式碼後加上的註解),那麼方法1,2即突顯出了"排除try..catch"與"省略每次建立instance"兩個改善後節省的時間。不過依我的認知,try...catch在沒有發生Exception時是否會拖累效能的,好奇之餘,我做了一個測試: http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/12/20/try-catch-performance.aspx
Left by Darkthread 回覆 on 2009/12/20 下午 04:41

標題*
姓名*
電子郵件 (never displayed)
 
個人網頁
回覆*

登入後使用進階評論
Please add 1 and 7 and type the answer here: