C# 效能最佳化最佳實務

來源:互聯網
上載者:User
1、顯式註冊的EvenHandler要顯式登出以避免記憶體流失

將一個成員方法註冊到某個對象的事件會造成後者持有前者的引用。在事件登出之前,前者不會被記憶體回收。

private void Form1_Load(){  ……  //註冊事件  CommandRemotingContext.CmdChanged += new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged);  ……}private void Form1_FromClosed(){  ……  //關閉表單時及時釋放事件  CommandRemotingContext.CmdChanged -= new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged);  ……}

由事件引起的記憶體流失問題:

  • 對象A訂閱了對象B中的事件

  • 對象A的生命週期遠遠大於對象B

  • 對象A沒有取消訂閱對象B的時間

  • 最終導致對象B無法釋放


2、控制項繫結資料源大量操作應避免自動重新整理

  • 用戶端大量操作資料時,控制項內建的重新整理操作,會造成不必要的時間消耗

  • 當資料來源(如DataTable、Array、List、ObservableCollection或其他IListSource等)被綁定到控制項時,大量操作資料時應該斷開綁定或掛起控制項的重新整理。

    this.gcBillList.DataSource = null;DataRowCollection rows = this.ds.Tables[0].Rows;foreach (DataRow row in rows){    // DataRow資料操作}this.gcBillList.DataSource = this.ds.Tables[0].DefaultView;

3、減少用戶端與服務端的通訊次數


  • WebService調用並非越少越好,傳輸資料量較大的情況可考慮拆分為多次調用

  • 對於短WebService的調用,應盡量合并以減少互動次數

    //多次調用了相同的WS  txtCompanyName.Text=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyNameByID”,“0001”);  txtCompanyInnerName.Text=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyInnerNameByID”,“0001”);//合并相鄰的WS  string[] result=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyNameAndInnerNameByID”,“0001”);txtCompanyName.Text=result[0];txtCompanyInnerName.Text= result[1];

4、減少用戶端與服務端的通訊次數

如非必要,應盡量避免在迴圈體內重複調用WebService

//迴圈調用了相同的WS  List<Person> persons;……foreach(string personID in personIDs){person=HRPubWsClient.getPerson(personID);persons.Add(person);}//合并WS  List<Person> persons;……persons =HRPubWsClient.getPersonList(personIDs);

5、使用泛型來避免裝箱、拆箱操作(減少記憶體回收壓力)

  • 裝箱操作會造成GC壓力;如果發生在集合中,應該使用泛型集合避免。

  • 對於實值型別的集合,使用List<T>來代替ArrayList,使用Dictionary<TKey, TValue> 來代替Hashtable。

    ArrayList h=new ArrayList();  //不建議h.Add(1); List<object> h = new List<object>();  //不建議h.Add(1); List<int> h = new List<int>();    //建議h.Add(1);

6、字串操作:

C# 字串操作--減少記憶體回收壓力
7、使用常量避免建立對象

  • 如下例,程式中存在大量 new decimal(0)的代碼,這會導致小對象頻繁建立及回收;正確的做法是使用 Decimal.Zero 常量。

    private string CurrencyCalc(){    if (firstValue == new decimal(0))  ……    if (secondValue == new decimal(0)) ……    if (thirdValue == new decimal(0)) ……    if (fourthValue == new decimal(0)) ……    ……}

8、避免不必要的拋出異常

C# 異常處理(Catch Throw)IL分析

9、使用RemoveAll而非RemoveAt進行刪除多個元素

  • 使用RemoveAll方法對集合(如List)中的多個元素進行一次性刪除時,只會對List的內部數組做一次resize 操作,效率明顯高於迴圈調用RemoveAt。

    List<string>  lst = new List<string> {"1", "2", "3", "1", "2", "4"};//不建議:for (int i = lst.Count - 1; i >= 0; i--){    if (lst[i] == "1" || lst[i] == "2")    {        lst.RemoveAt(i);     }} //建議:lst.RemoveAll(s => s == "1" || s == "2");

10、C# DataSet效能最佳實務

11、反射與動態綁定--減少CPU佔用

  • 反射技術是將編譯期間的靜態繫結轉換為延遲到運行期間的動態綁定。

  • C#主要支援 5 種動態建立對象的方式(時間消耗來自網路,與我實測的差距挺大,具體測試見下方):

動態建立對象的方式
與Direct Create
1.Type.InvokeMember
慢40倍以上
2.ContructorInfo.Invoke
慢40倍以上
3.Activator.CreateInstance(Type)
慢7倍
4.Activator.CreateInstance(assemblyName, typeName)
慢1000倍以上
5.Assembly.CreateInstance(typeName)
慢40倍以上

  • 應盡量避免使用反射和動態綁定;如必須使用,要遵循以下原則:

1. 使用介面調用方式將動態綁定改造為早期繫結(Direct Call)
2. 使用 Activator.CreateInstance(Type)方式動態建立對象

3. 使用typeof操作符代替GetType調用

小註:

通過迴圈建立執行個體記錄時間如下:

載入程式集、擷取類型在迴圈外部時間如下(這時不同建立方式消耗時間差距挺大):


代碼如下:

 public void TestCreateInstance()        {            Stopwatch watch1 = new Stopwatch();            var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");            Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");            int num = 100000;            watch1.Start();            for (int i = 0; i < num; i++)            {                //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");                //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");                Activator.CreateInstance(type);            }            watch1.Stop();            label1.Text = "Activator.CreateInstance(Type type)時間:" + watch1.ElapsedMilliseconds + "毫秒";            watch1.Reset();            watch1.Start();            for (int i = 0; i < num; i++)            {                Activator.CreateInstance("ReflectiveClassLibrary", "ReflectiveClassLibrary.TestClass");            }            watch1.Stop();            label2.Text = "Activator.CreateInstance(string assemblyName,string typeName)時間:" + watch1.ElapsedMilliseconds + "毫秒";            watch1.Reset();            watch1.Start();            for (int i = 0; i < num; i++)            {                //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");                //載入程式集                                asmb.CreateInstance("TestClass");            }            watch1.Stop();            label3.Text = "assembly.CreateInstance(string typeName)時間:" + watch1.ElapsedMilliseconds + "毫秒";            watch1.Reset();            watch1.Start();            for (int i = 0; i < num; i++)            {                //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");                //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");                object obj = type.InvokeMember(null, BindingFlags.Public |               BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null);            }            watch1.Stop();            label4.Text = "Type.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args)時間:" + watch1.ElapsedMilliseconds + "毫秒";            watch1.Reset();            watch1.Start();            for (int i = 0; i < num; i++)            {                //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");                //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");                ConstructorInfo constructorInfo = type.GetConstructors()[0];                constructorInfo.Invoke(null);            }            watch1.Stop();            label5.Text = "ContructorInfo.Invoke(object[] parameters)時間:" + watch1.ElapsedMilliseconds + "毫秒";        }


載入程式集、擷取類型在迴圈內部時間如下(這時不同建立方式消耗時間差距比較小):


代碼如下:

 public void TestCreateInstance()        {            Stopwatch watch1 = new Stopwatch();            //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");            //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");            int num = 100000;            watch1.Start();            for (int i = 0; i < num; i++)            {                var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");                Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");                Activator.CreateInstance(type);            }            watch1.Stop();            label1.Text = "Activator.CreateInstance(Type type)時間:" + watch1.ElapsedMilliseconds + "毫秒";            watch1.Reset();            watch1.Start();            for (int i = 0; i < num; i++)            {                Activator.CreateInstance("ReflectiveClassLibrary", "ReflectiveClassLibrary.TestClass");            }            watch1.Stop();            label2.Text = "Activator.CreateInstance(string assemblyName,string typeName)時間:" + watch1.ElapsedMilliseconds + "毫秒";            watch1.Reset();            watch1.Start();            for (int i = 0; i < num; i++)            {                var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");                //載入程式集                                asmb.CreateInstance("TestClass");            }            watch1.Stop();            label3.Text = "assembly.CreateInstance(string typeName)時間:" + watch1.ElapsedMilliseconds + "毫秒";            watch1.Reset();            watch1.Start();            for (int i = 0; i < num; i++)            {                var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");                Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");                object obj = type.InvokeMember(null, BindingFlags.Public |               BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null);            }            watch1.Stop();            label4.Text = "Type.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args)時間:" + watch1.ElapsedMilliseconds + "毫秒";            watch1.Reset();            watch1.Start();            for (int i = 0; i < num; i++)            {                var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");                Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");                ConstructorInfo constructorInfo = type.GetConstructors()[0];                constructorInfo.Invoke(null);            }            watch1.Stop();            label5.Text = "ContructorInfo.Invoke(object[] parameters)時間:" + watch1.ElapsedMilliseconds + "毫秒";        }


測試代碼如下:

c# 反射測試demo

12、序列化與還原序列化

  • 相對於XML、二進位序列化方式,Protobuf效率較高,支援資料量較大

  • protobuf序列化後的大小是json的1/10,xml格式的1/20,是二進位序列化的1/10

以上就是C# 效能最佳化最佳實務的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.