ホームページ >バックエンド開発 >C#.Net チュートリアル >C# パフォーマンス最適化のベスト プラクティス
1. メモリリークを避けるために、明示的に登録された EvenHandler は明示的に登録解除される必要があります
オブジェクトのイベントにメンバーメソッドを登録すると、後者は前者への参照を保持します。前者は、イベントがログアウトされるまでガベージ コレクションされません。
rreeeememoryイベントによって引き起こされる漏れの問題:
2. コントロールにバインドされたデータ ソースのバッチ操作は自動更新を回避する必要があります
データソース(DataTable、Array、List、ObservableCollectionまたは他のIListSourceなど)が、など) ) がコントロールにバインドされている場合、データをバッチで操作する場合は、バインドを切断するか、コントロールの更新を一時停止する必要があります。 private void Form1_Load()
{
……
//注册事件
CommandRemotingContext.CmdChanged += new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged);
……
}
private void Form1_FromClosed()
{
……
//关闭窗体时及时释放事件
CommandRemotingContext.CmdChanged -= new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged);
……
}
送信されるデータの量が多い場合は、分割することを検討してください。複数の呼び出しに分割します
短い WebService 呼び出しの場合は、対話の数を減らすために可能な限りマージする必要があります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;
//多次调用了相同的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];
5. ジェネリックスを使用してボックス化およびボックス化解除操作を回避します (ガベージ コレクションの圧力を軽減します)
ボックス化操作により GC プレッシャーが発生します。これがコレクションで発生した場合は、ジェネリック コレクションを使用してこれを回避する必要があります。
//循环调用了相同的WS
List<Person> persons;
……
foreach(string personID in personIDs)
{
person=HRPubWsClient.getPerson(personID);
persons.Add(person);
}
//合并WS
List<Person> persons;
……
persons =HRPubWsClient.getPersonList(personIDs);
以下の例のように、プログラム内の多くの部分で新しい decimal(0) コードが使用されるため、小さなオブジェクトが頻繁に作成され、リサイクルされます。正しいアプローチは、Decimal.Zero 定数を使用することです。 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);
9. 複数の要素を削除するには、RemoveAt の代わりに RemoveAll を使用します
RemoveAll メソッドを使用してコレクション (List など) 内の複数の要素を一度に削除する場合、List の内部配列に対してサイズ変更操作が 1 回だけ実行されます。これは、ループ内で RemoveAt を呼び出すよりも大幅に効率的です。
private string CurrencyCalc() { if (firstValue == new decimal(0)) …… if (secondValue == new decimal(0)) …… if (thirdValue == new decimal(0)) …… if (fourthValue == new decimal(0)) …… …… }
11. リフレクションと動的バインディング -- CPU 使用率を削減
リフレクション テクノロジは、コンパイル時の静的バインディングを実行時の動的バインディングの遅延に変換します。
动态创建对象的方式 |
与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)!