web-dev-qa-db-fra.com

Performance des méthodes statiques vs méthodes d'instance

Ma question concerne les caractéristiques de performance des méthodes statiques par rapport aux méthodes d'instance et leur évolutivité. Supposons pour ce scénario que toutes les définitions de classe se trouvent dans un seul assemblage et que plusieurs types de pointeurs discrets sont requis.

Considérer:

public sealed class InstanceClass
{
      public int DoOperation1(string input)
      {
          // Some operation.
      }

      public int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more instance methods.
}

public static class StaticClass
{
      public static int DoOperation1(string input)
      {
          // Some operation.
      }

      public static int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more static methods.
}

Les classes ci-dessus représentent un modèle de style d'assistance.

Dans une classe d'instance, la résolution de la méthode d'instance prend un moment pour s'opposer à StaticClass.

Mes questions sont:

  1. Lorsque le maintien de l'état n'est pas une préoccupation (aucun champ ni aucune propriété n'est requis), est-il toujours préférable d'utiliser une classe statique?

  2. Là où il y a un nombre considérable de ces définitions de classes statiques (100 par exemple, avec un nombre de méthodes statiques chacune), cela affectera-t-il les performances d'exécution ou la consommation de mémoire de manière négative par rapport au même nombre de définitions de classes d'instances?

  3. Lorsqu'une autre méthode de la même classe d'instance est appelée, la résolution d'instance se produit-elle toujours? Par exemple, en utilisant le mot clé [this] comme this.DoOperation2("abc") dans DoOperation1 De la même instance.

101
Bernie White

En théorie, une méthode statique devrait fonctionner légèrement mieux qu'une méthode d'instance, toutes choses étant égales par ailleurs, en raison du paramètre supplémentaire caché this.

En pratique, cela fait tellement peu de différence qu'il sera caché dans le bruit des différentes décisions du compilateur. (Par conséquent, deux personnes pourraient "prouver" l'une meilleure que l'autre avec des résultats discordants). Notamment parce que le this est normalement passé dans un registre et est souvent dans ce registre pour commencer.

Ce dernier point signifie qu'en théorie, nous devrions nous attendre à une méthode statique qui prenne un objet en paramètre et qui en fait quelque chose soit légèrement moins bonne que son équivalent en tant qu'instance sur ce même objet. Encore une fois cependant, la différence est si faible que si vous essayez de la mesurer, vous finirez probablement par mesurer une autre décision du compilateur. (Surtout depuis que la probabilité que cette référence soit dans un registre tout le temps est assez haute aussi).

Les différences de performances réelles vont dépendre du fait que vous avez artificiellement des objets en mémoire pour faire quelque chose qui devrait naturellement être statique, ou que vous emmêlez des chaînes d'objet passant de manière compliquée pour faire ce qui devrait naturellement être une instance.

Par conséquent, pour le numéro 1. Lorsque le maintien de l'état n'est pas une préoccupation, il est toujours préférable d'être statique, , car c'est à cela que sert statique . Ce n’est pas un problème de performances, bien qu’il existe une règle générale permettant de bien jouer avec les optimisations du compilateur: il est plus probable que l’on essaie d’optimiser les cas qui aboutissent à une utilisation normale à ceux qui aboutissent à une utilisation étrange.

Numéro 2. ne fait aucune différence. Il y a un certain coût par classe pour chaque membre en termes de métadonnées, de code dans le fichier DLL ou EXE, et de code jitted). Ce sera la même chose, qu'il s'agisse d'instance ou de statique.

Avec l'élément 3, this est comme this. Notez cependant:

  1. Le paramètre this est transmis dans un registre particulier. Lorsque vous appelez une méthode d'instance dans la même classe, il est probable qu'elle se trouve déjà dans ce registre (sauf si elle a été stockée et que le registre a été utilisé pour une raison quelconque). Par conséquent, aucune action n'est requise pour définir le paramètre this sur ce à quoi il doit être réglé. Ceci s’applique dans une certaine mesure, par exemple: les deux premiers paramètres de la méthode étant les deux premiers paramètres d'un appel passé.

  2. Comme il est clair que this n'est pas null, cela peut être utilisé pour optimiser les appels dans certains cas.

  3. Comme il est clair que this n'est pas null, cela peut rendre les appels de méthode en ligne plus efficaces, car le code produit pour simuler l'appel de méthode peut omettre certaines vérifications nulles dont il pourrait avoir besoin de toute façon.

  4. Cela dit, les chèques nuls ne coûtent pas cher!

Il est à noter que les méthodes statiques génériques agissant sur un objet, plutôt que les méthodes d'instance, peuvent réduire certains des coûts décrits à l'adresse http: //joeduffyblog.com/2011/10/23/on-generics-and- une partie de la surcharge / dans le cas où cette donnée statique n'est pas appelée pour un type donné. Comme il le dit "De plus, il s'avère que les méthodes d'extension sont un excellent moyen de rendre les abstractions génériques plus payantes."

Cependant, notez que cela ne concerne que l'instanciation d'autres types utilisés par la méthode, qui n'existent pas par ailleurs. En tant que tel, cela ne s'applique vraiment pas à beaucoup de cas (une autre méthode d'instance utilisait ce type, un autre code ailleurs utilisait ce type).

Sommaire:

  1. Généralement, les coûts de performance de l'instance vs statique sont inférieurs à négligeables.
  2. Les coûts qui en résultent viendront généralement lorsque vous abusez de l'électricité statique par exemple ou inversement. Si vous ne faites pas partie de votre décision entre statique et instance, vous aurez plus de chances d'obtenir le résultat correct.
  3. Il existe de rares cas où les méthodes génériques statiques d'un autre type entraînent la création de moins de types que les méthodes génériques d'instance, ce qui peut parfois présenter un petit avantage. to turn rarement utilisé (et "rarement" se réfère aux types avec lesquels il est utilisé dans la vie de l'application, pas à quelle fréquence il est appelé). Une fois que vous aurez compris ce dont il parle dans cet article, vous constaterez que cela n’est de toute façon pas pertinent pour la plupart des décisions statiques vs instances. Edit: Et cela n’a généralement que ce coût avec ngen, pas avec du code jitted.

Edit: Une note sur le coût nul des chèques nuls (ce que j’ai affirmé plus haut). La plupart des vérifications nulles dans .NET ne vérifient pas null du tout, mais continuent ce qu'elles allaient faire en supposant que cela fonctionnerait, et si une exception d'accès se produit, elle est transformée en un NullReferenceException. En tant que tel, la plupart du temps, lorsque le code C # implique un contrôle nul parce qu'il accède à un membre de l'instance, le coût en cas de succès est en réalité de zéro. Une exception serait quelques appels en ligne (parce qu'ils veulent se comporter comme s'ils appelaient un membre d'instance) et qu'ils frappaient simplement un champ pour déclencher le même comportement. Ils sont donc aussi très bon marché et peuvent toujours être laissés de côté. (par exemple, si la première étape de la méthode impliquait l’accès à un champ tel quel).

141
Jon Hanna

Lorsque le maintien de l'état n'est pas une préoccupation (aucun champ ni aucune propriété n'est requis), est-il toujours préférable d'utiliser une classe statique?

Je dirais oui. En déclarant quelque chose static vous déclarez un intention d'exécution sans état (ce n'est pas obligatoire, mais l'intention de quelque chose auquel on pourrait s'attendre)

Là où il y a un nombre considérable de ces classes statiques (100 par exemple, avec un nombre de méthodes statiques chacune), cela affectera-t-il les performances d'exécution ou la consommation de mémoire de manière négative par rapport au même nombre de classes d'instances?

Ne pensez pas, sauf si vous êtes sûr que les classes statiques sont vraiment stetless, sinon, c'est facile de gâcher les allocations de mémoire et d'obtenir des fuites de mémoire.

Lorsque le mot clé [this] est utilisé pour appeler une autre méthode dans la même classe d'instance, la résolution d'instance se produit-elle toujours?

Pas sûr, à propos de this point (ceci est un détail de mise en œuvre de CLR), mais pensez oui.

7
Tigran

les méthodes statiques sont plus rapides mais moins efficaces, si vous utilisez des modèles de conception, une méthode statique peut-être un mauvais code, pour écrire de la logique métier mieux sans fonctions statiques communes, telles que la lecture de fichier, WebRequest, etc. répondre

0
burning_LEGION