程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#性能優化之斤斤計較篇一

C#性能優化之斤斤計較篇一

編輯:C#入門知識

今天,我想跟大家聊一聊C#的性能優化,當然,這裡並不談基本的原則,這些都假設你已經非常精通了,本文聊的是要爭取幾個毫秒的程序。關於基本的性能優化,可以參考園子裡的文章。比如:

.NET 性能優化方法總結

先說說我的測試環境:

 \


 

一台典型的筆記本電腦,Windows 7中文版,.net Framework用的是4.5版本,VS是現在VS11 beta版。我也是用VS2008這樣的環境測試了下面的所有場景,發現沒有任何區別,所以就以VS11為基准了。
所有測試數據都是編譯為Relase,且不包含PDB,直接雙擊運行而非在VS環境下執行。點擊這裡http://www.BkJia.com/uploadfile/2012/0516/20120516091804678.rar
下載源代碼。
言歸正傳,先測試第一點:
 
靜態方法比實例方法快嗎?
我們總是從各個渠道聽說:靜態方法比實例方法要快,所以,我想親自試試。測試方法很簡單,循環調用實例方法和靜態方法。

/// <summary>
/// 這是一個普通類,調用實例的方法
/// </summary>
public class C1 {
    public void DoLoop() {
        for (int i = 0; i < int.MaxValue; i++) {
            DoIt();
        } 
    }
 
    private void DoIt() {
    }
}
 
/// <summary>
/// 使用靜態方法調用。
/// </summary>
public static class C2 {
    public static void DoLoop() {
        for (int i = 0; i < int.MaxValue; i++) {
            DoIt();
        }
    }
 
    private static void DoIt() {
    }
}
測試結果如下:

\
 
測試多次,基本偏差不大,只能說,靜態方法比實例方法快那麼可憐的一點點,鑒於實例方法的靈活性遠大於靜態方法,所以還是一般使用實例方法吧。
也實驗過,在方法中訪問實例字段和靜態字段,發現也沒有區別,所以不再單獨羅列代碼。
 
避免方法內創建實例的情況
這個要討論的問題有點難說明,我們還是先看一看.net內部的代碼吧,下面是一段Collection<T>.Add的方法:
 public void Add(T item)
{
    if (this.items.IsReadOnly)
    {
        ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
    }
    int count = this.items.Count;
    this.InsertItem(count, item);
}
注意ThrowHelper類,如果換成我們自己寫,一句話就搞定了:throw new NotSupportedException。為什麼微軟要這麼寫呢?
老外有解釋:Why does SortedList implementation use ThrowHelper instead of throwing directly?
其實,我也是信奉此真理,而且就在前一段時間,一位同事還找我問,兩段幾乎一樣的代碼,為什麼測試性能有差距,結果我按照此原理,將異常拋出放在外面,結果真的變好了。
現在,我還要再次測試一下,我相信的是數據:
?
class C1 {
    private Dictionary<int, int> _dict = new Dictionary<int, int>() ;
    public C1() {
        _dict.Add(1, 1);
        _dict.Add(2, 2);
    }
 
    public void Do1() {
        object obj = new object();
        for (int i = 0; i < int.MaxValue/100; i++) {
            GetItOne(1);
        }
    }
 
    //這個方法,在內部可能創建實例
    private int GetItOne(int key) {
        int value;
        if (!_dict.TryGetValue(key,out value)) {
            throw new ArgumentOutOfRangeException("key");
        }
        return value;
    }
 
    public void Do2() {
        for (int i = 0; i < int.MaxValue/100; i++) {
            GetItTwo(1);
        }
    }
 
    //這個方法,將創建實例的代碼移動到外部
    private int GetItTwo(int key) {
        int value;
        if (!_dict.TryGetValue(key, out value)) {
            ThrowArgumentOutOfRangeException();
        }
        return value;
    }
 
    private static void ThrowArgumentOutOfRangeException() {
        throw new ArgumentOutOfRangeException("key");
    }
}
測試結果是:
\
 
基本上,會快0.06秒左右,但是如此大的循環得到的好處並不是那麼的明顯,但有作用。這種寫法還是比較舒服的,所以還是建議大家用吧。
 
下篇我將實驗:數組的枚舉,類和結構創建的成本。

 


摘自 編寫人生

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved