Home > Article > Backend Development > C# performance optimization best practices
1. The explicitly registered EvenHandler must be explicitly unregistered to avoid memory leaks
Registering a member method to an event of an object will cause the latter to hold A reference to the former. The former will not be garbage collected until the event is logged out.
##
private void Form1_Load() { …… //注册事件 CommandRemotingContext.CmdChanged += new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged); …… } private void Form1_FromClosed() { …… //关闭窗体时及时释放事件 CommandRemotingContext.CmdChanged -= new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged); …… }
Memory leak problem caused by events:
Object A subscribes to events in object B
The life cycle of object A is much longer than that of object B
Object A does not unsubscribe from object B
Eventually, object B cannot be released
2. Batch operations on the data source bound to the control should avoid automatic refresh
When the client operates data in batches, the refresh operation of the control will cause unnecessary time consumption
When the data source (such as When a DataTable, Array, List, ObservableCollection or other IListSource, etc.) is bound to a control, you should disconnect the binding or suspend the refresh of the control when operating data in batches.
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. Reduce the number of communications between the client and the server
The fewer WebService calls, the better. If the amount of data to be transmitted is large, consider splitting it into multiple calls.
For short WebService calls, they should be merged as much as possible to reduce the number of interactions
//多次调用了相同的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. Reduce the number of communications between the client and the server
If not necessary, try to avoid calling WebService repeatedly in the loop body
##//循环调用了相同的WS
List<Person> persons;
……
foreach(string personID in personIDs)
{
person=HRPubWsClient.getPerson(personID);
persons.Add(person);
}
//合并WS
List<Person> persons;
……
persons =HRPubWsClient.getPersonList(personIDs);
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);
C# String operation--reduce Garbage collection pressure7. Use constants to avoid creating objects
private string CurrencyCalc()
{
if (firstValue == new decimal(0)) ……
if (secondValue == new decimal(0)) ……
if (thirdValue == new decimal(0)) ……
if (fourthValue == new decimal(0)) ……
……
}
C# Exception handling ( Catch Throw) IL analysis
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");
11. Reflection and dynamic binding--reduce CPU Occupy
动态创建对象的方式 |
与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# 性能优化最佳实践的内容,更多相关内容请关注PHP中文网(www.php.cn)!