Meilleures pratiques d'optimisation des performances C#

黄舟
Libérer: 2017-02-25 11:04:45
original
1853 Les gens l'ont consulté

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);
  ……
}
Copier après la connexion

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;
    Copier après la connexion

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];
    Copier après la connexion

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);
Copier après la connexion

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 List au lieu de ArrayList et utilisez Dictionary

    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);
    Copier après la connexion

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)) ……
        ……
    }
    Copier après la connexion

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");
    Copier après la connexion

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 + "毫秒";

        }
Copier après la connexion


加载程序集、获取类型在循环内部时间如下(这时不同创建方式消耗时间差距比较小)


代码如下:

 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 + "毫秒";

        }
Copier après la connexion


测试代码如下:

c# 反射测试demo
Copier après la connexion

12、序列化与反序列化

  • 相对于XML、二进制序列化方式,Protobuf效率较高,支持数据量较大

  • protobuf序列化后的大小是json的1/10,xml格式的1/20,是二进制序列化的1/10

 以上就是C# 性能优化最佳实践的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!