Maison > Article > développement back-end > Meilleures pratiques d'optimisation des performances C#
1. L'EvenHandler explicitement enregistré doit être explicitement désenregistré pour éviter les fuites de mémoire.
L'enregistrement d'une méthode membre à un événement d'un objet entraînera la détention d'une référence par ce dernier. au premier. Les premiers ne seront pas récupérés jusqu'à ce que l'événement soit déconnecté.
private void Form1_Load() { …… //注册事件 CommandRemotingContext.CmdChanged += new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged); …… } private void Form1_FromClosed() { …… //关闭窗体时及时释放事件 CommandRemotingContext.CmdChanged -= new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged); …… }
Problème de fuite de mémoire causé par des événements :
L'objet A s'abonne aux événements de l'objet B
Le cycle de vie de l'objet A est bien plus long que celui de l'objet B
Le moment où l'objet A ne s'est pas désabonné de l'objet B
a finalement amené l'objet B à ne pas pouvoir être publié
2. Les opérations par lots de sources de données liées aux contrôles doivent éviter l'actualisation automatique
Lorsque le client exploite les données par lots, l'opération de rafraîchissement du contrôle entraînera une consommation de temps inutile
Lorsque les données Lorsqu'une source (telle que DataTable, Array, List, ObservableCollection ou autre IListSource, etc.) est liée à un contrôle, la liaison doit être déconnectée ou l'actualisation du contrôle doit être suspendue lors de l'exploitation des données dans lots.
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. Réduire le nombre de communications entre le client et le serveur
Moins d'appels WebService n'est pas toujours préférable. Si la quantité de données à transmettre est importante, pensez à la diviser en plusieurs appels
Pour les appels WebService courts, ils doivent être fusionnés autant que possible pour réduire le nombre d'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. le nombre de communications entre le client et le serveur
Si cela n'est pas nécessaire, essayez d'éviter d'appeler WebService à plusieurs reprises dans le corps de la boucle
//循环调用了相同的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. Utiliser des génériques pour éviter les opérations de mise en boîte et de déballage (réduire la pression de la collecte des déchets)
Les opérations de boxe provoqueront du GC Stress si elles se produisent dans les collections, elles doivent être évitées en utilisant des collections génériques.
Pour les collections de types de valeurs, utilisez List8742468051c85b06f0a0af9e3e506b5c au lieu de ArrayList et utilisez Dictionaryb6842da76bed01162354d37c4f2d3464
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. Opération de chaîne :
Opération de chaîne C# - -Réduire pression de collecte des ordures7. Utilisez des constantes pour éviter de créer des objets
Comme le montre l'exemple suivant, il existe de nombreux nouveaux codes décimaux (0). dans le programme, ce qui entraînera la création et le recyclage fréquents de petits objets ; la bonne approche consiste à utiliser la constante 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. Évitez les exceptions inutiles
Traitement des exceptions C# (Catch Throw ) Analyse IL
9. Utilisez RemoveAll au lieu de RemoveAt pour supprimer plusieurs éléments
Lors de l'utilisation du RemoveAll pour supprimer plusieurs éléments d'une collection (telle que List) en même temps, une seule opération de redimensionnement sera effectuée sur le tableau interne de List, ce qui est nettement plus efficace que d'appeler RemoveAt dans une boucle.
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. Meilleures pratiques en matière de performances de C# DataSet
11. Réflexion et liaison dynamique - Réduire le processeur utilisation
La technologie Reflection convertit la liaison statique lors de la compilation en liaison dynamique qui est retardée à l'exécution.
C# supporte principalement 5 façons de créer dynamiquement des objets (la consommation de temps vient du réseau, ce qui est assez différent de ma mesure réelle. Voir le test spécifique ci-dessous) :
动态创建对象的方式 |
与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)!