Leistung statischer Methoden gegenüber Instanzmethoden


108

Meine Frage bezieht sich auf die Leistungsmerkmale statischer Methoden gegenüber Instanzmethoden und deren Skalierbarkeit. Angenommen, für dieses Szenario befinden sich alle Klassendefinitionen in einer einzelnen Assembly und es sind mehrere diskrete Zeigertypen erforderlich.

Erwägen:

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.
}

Die obigen Klassen repräsentieren ein Hilfsstilmuster.

In einer Instanzklasse dauert es einen Moment, bis die Instanzmethode aufgelöst ist, im Gegensatz zu StaticClass.

Meine Fragen sind:

  1. Wenn es nicht darum geht, den Status beizubehalten (es sind keine Felder oder Eigenschaften erforderlich), ist es immer besser, eine statische Klasse zu verwenden?

  2. Wenn es eine beträchtliche Anzahl dieser statischen Klassendefinitionen gibt (z. B. 100 mit jeweils einer Anzahl statischer Methoden), wirkt sich dies negativ auf die Ausführungsleistung oder den Speicherverbrauch im Vergleich zur gleichen Anzahl von Instanzklassendefinitionen aus?

  3. Tritt die Instanzauflösung immer noch auf, wenn eine andere Methode innerhalb derselben Instanzklasse aufgerufen wird? Verwenden Sie beispielsweise das Schlüsselwort [this] wie this.DoOperation2("abc")innerhalb DoOperation1derselben Instanz.



Was meinst du mit "Instanzauflösung"? Auf IL-Ebene ist "dieser" Zeiger wie jede andere lokale Variable verfügbar. Tatsächlich könnten Sie in einigen alten CLR / JIT-Versionen eine Instanzmethode für NULL aufrufen, vorausgesetzt, sie hat das 'this' nicht berührt - der Code ist nur durchgeflogen und auf nichts abgestürzt. Jetzt enthält CLR / JIT explizite Null- Überprüfen Sie auf jedes Mitglied aufrufen ..
Quetzalcoatl

> vijaymukhi.com/documents/books/ilbook/chap8.htm und 'Instanz aufrufen' versus nur 'Anruf'. Ersteres erwartet 'diesen' Parameter und letzteres nicht.
Quetzalcoatl

@Quetzalcoatl Entschuldigung für die Verwirrung, die Frage war mehr Methode zu Methode von derselben Instanz und wenn das erfordert, dass die Instanz in sich selbst aufgelöst wird.
Bernie White

1
@quetzalcoatl Ich nahm an, er meinte: "Wird der Compiler die Überprüfung, die thisauf etwas verweist , los , wenn eine Klasse eine Instanzmethode für sich selbst aufruft?"
Jon Hanna

Antworten:


152

Theoretisch sollte eine statische Methode etwas besser abschneiden als eine Instanzmethode, da alle anderen Dinge aufgrund des zusätzlichen versteckten thisParameters gleich sind.

In der Praxis macht dies so wenig Unterschied, dass es im Rauschen verschiedener Compilerentscheidungen verborgen bleibt. (Daher könnten zwei Personen eine Person mit nicht übereinstimmenden Ergebnissen besser "beweisen" als die andere). Nicht zuletzt, weil das thisnormalerweise in einem Register übergeben wird und sich oft in diesem Register befindet.

Dieser letzte Punkt bedeutet, dass wir theoretisch erwarten sollten, dass eine statische Methode, die ein Objekt als Parameter verwendet und etwas damit macht, etwas weniger gut ist als das Äquivalent als Instanz für dasselbe Objekt. Auch hier ist der Unterschied so gering, dass Sie, wenn Sie versuchen würden, ihn zu messen, wahrscheinlich eine andere Compilerentscheidung messen würden. (Zumal die Wahrscheinlichkeit, dass sich diese Referenz die ganze Zeit in einem Register befindet, auch ziemlich hoch ist).

Die tatsächlichen Leistungsunterschiede hängen davon ab, ob Sie Objekte künstlich im Speicher haben, um etwas zu tun, das natürlich statisch sein sollte, oder ob Sie Ketten der Objektübergabe auf komplizierte Weise verwickeln, um das zu tun, was natürlich Instanz sein sollte.

Daher für Nummer 1. Wenn es kein Problem ist, den Status beizubehalten, ist es immer besser, statisch zu sein, denn dafür ist statisch gedacht . Es ist kein Leistungsproblem, obwohl es eine allgemeine Regel gibt, mit Compiler-Optimierungen gut zu spielen - es ist wahrscheinlicher, dass sich jemand die Mühe gemacht hat, Fälle zu optimieren, die bei normaler Verwendung auftreten, als solche, die bei seltsamer Verwendung auftreten.

Nummer 2. Macht keinen Unterschied. Es gibt eine bestimmte Menge an Kosten pro Klasse für jedes Mitglied, die sowohl davon abhängt, wie viele Metadaten vorhanden sind, wie viel Code in der tatsächlichen DLL- oder EXE-Datei vorhanden ist, als auch davon, wie viel Jitted-Code vorhanden sein wird. Dies ist gleich, ob es sich um eine Instanz oder eine statische Instanz handelt.

Mit Punkt 3 thisist wie this. Beachten Sie jedoch:

  1. Der thisParameter wird in einem bestimmten Register übergeben. Wenn Sie eine Instanzmethode innerhalb derselben Klasse aufrufen, befindet sie sich wahrscheinlich bereits in diesem Register (es sei denn, sie wurde gespeichert und das Register aus irgendeinem Grund verwendet). Daher ist keine Aktion erforderlich, um das thisauf das zu setzen , worauf es eingestellt werden muss . Dies gilt bis zu einem gewissen Grad, z. B. wenn die ersten beiden Parameter der Methode die ersten beiden Parameter eines Aufrufs sind.

  2. Da klar thisist , dass dies nicht null ist, kann dies in einigen Fällen zur Optimierung von Anrufen verwendet werden.

  3. Da klar thisist , dass dies nicht null ist, kann dies dazu führen, dass inline-Methodenaufrufe wieder effizienter werden, da der Code, der zum Fälschen des Methodenaufrufs erstellt wird, einige ohnehin erforderliche Nullprüfungen weglassen kann.

  4. Das heißt, Nullschecks sind billig!

Es ist erwähnenswert, dass generische statische Methoden, die auf ein Objekt und nicht auf Instanzmethoden einwirken, einen Teil der unter http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- diskutierten Kosten reduzieren können. die zugehörigen Gemeinkosten / in dem Fall, in dem die angegebene Statik für einen bestimmten Typ nicht aufgerufen wird. Wie er es ausdrückt "Nebenbei bemerkt, es stellt sich heraus, dass Erweiterungsmethoden eine großartige Möglichkeit sind, generische Abstraktionen mehr für das Spiel zu bezahlen."

Beachten Sie jedoch, dass dies nur die Instanziierung anderer von der Methode verwendeter Typen betrifft, die ansonsten nicht vorhanden sind. Als solches trifft es wirklich nicht auf viele Fälle zu (eine andere Instanzmethode verwendete diesen Typ, ein anderer Code irgendwo anders verwendete diesen Typ).

Zusammenfassung:

  1. Meistens sind die Leistungskosten der Instanz gegenüber der statischen unter vernachlässigbar.
  2. Welche Kosten dort anfallen, wird in der Regel dort anfallen, wo Sie beispielsweise statische Aufladung missbrauchen oder umgekehrt. Wenn Sie es nicht zu einem Teil Ihrer Entscheidung zwischen statisch und Instanz machen, erhalten Sie mit größerer Wahrscheinlichkeit das richtige Ergebnis.
  3. Es gibt seltene Fälle, in denen statische generische Methoden in einem anderen Typ dazu führen, dass weniger Typen erstellt werden als generische Instanzmethoden, was dazu führen kann, dass es manchmal einen kleinen Vorteil hat, selten verwendet zu werden (und "selten" bezieht sich darauf, mit welchen Typen es in der verwendet wird Lebensdauer der Anwendung, nicht wie oft sie aufgerufen wird). Sobald Sie wissen, wovon er in diesem Artikel spricht, werden Sie feststellen, dass es für die meisten Entscheidungen zwischen statischen und instanziellen Instanzen ohnehin zu 100% irrelevant ist. Bearbeiten: Und es hat meistens nur diese Kosten mit ngen, nicht mit jitted Code.

Bearbeiten: Ein Hinweis darauf, wie billig Null-Checks sind (was ich oben behauptet habe). Die meisten Nullprüfungen in .NET prüfen überhaupt nicht auf Null, sondern setzen ihre Arbeit mit der Annahme fort, dass sie funktionieren wird. Wenn eine Zugriffsausnahme auftritt, wird sie zu einer NullReferenceException. Wenn der C # -Code konzeptionell eine Nullprüfung beinhaltet, weil er auf ein Instanzmitglied zugreift, sind die Kosten, wenn er erfolgreich ist, tatsächlich Null. Eine Ausnahme wären einige Inline-Aufrufe (weil sie sich so verhalten möchten, als hätten sie ein Instanzmitglied angerufen), und sie treffen nur ein Feld, um dasselbe Verhalten auszulösen. Daher sind sie auch sehr billig und können trotzdem oft weggelassen werden (zB wenn der erste Schritt in der Methode den Zugriff auf ein Feld wie es war).


Können Sie kommentieren, ob die Frage statisch oder instanz einen Einfluss auf die Cache-Kohärenz hat? Ist es wahrscheinlicher, dass das Vertrauen in das eine oder andere zu Cache-Fehlern führt? Gibt es einen guten Überblick darüber, warum?
Scriptocalypse

@scriptocalypse Nicht wirklich. Der Anweisungscache sieht keinen Unterschied, und auf dieser Ebene gibt es keinen großen Unterschied zwischen dem Zugriff auf Daten über thisoder über einen expliziten Parameter. Eine größere Auswirkung wäre hier, wie nahe Daten an verwandten Daten (Werttypfelder oder Arraywerte sind näher als Daten in Referenztypfeldern) und Zugriffsmuster liegen.
Jon Hanna

"Theoretisch sollten wir erwarten, dass eine statische Methode, die ein Objekt als Parameter verwendet und etwas damit macht, etwas weniger gut ist als das Äquivalent als Instanz für dasselbe Objekt." - Meinen Sie das, wenn die obige Beispielmethode verwendet wird? Parameter als Objekt statt String, nicht statisch ist besser? Beispiel: Meine statische Methode verwendet ein Objekt als Parameter, serialisiert es in einen String und gibt einen String zurück. schlagen Sie vor, in diesem Fall nicht statisch zu verwenden?
Batmaci

1
@batmaci Ich meine, es gibt eine gute Chance obj.DoSomehting(2), die etwas billiger wäre als, DoSomething(obj, 2)aber wie gesagt, der Unterschied ist so gering und hängt von winzigen Dingen ab, die bei der endgültigen Zusammenstellung möglicherweise anders ausfallen, dass es sich überhaupt nicht lohnt, sich Sorgen zu machen. Wenn Sie etwas tun, das so teuer ist (im Verhältnis zu den Unterschieden im Spiel), wie etwas zu einer Zeichenfolge zu serialisieren, ist es besonders sinnlos.
Jon Hanna

In dieser ansonsten hervorragenden Antwort fehlt eine, vielleicht offensichtliche, aber wichtige Sache: Eine Instanzmethode erfordert eine Instanz, und das Erstellen einer Instanz ist nicht billig. Selbst ein Standard ctorerfordert immer noch die Initialisierung aller Felder. Sobald Sie bereits eine Instanz haben, gilt diese Antwort ("alle anderen Dinge sind gleich"). Natürlich kann ein teures cctorGerät auch statische Methoden verlangsamen, aber das gilt nur beim ersten Aufruf und gilt gleichermaßen für Instanzmethoden. Siehe auch docs.microsoft.com/en-us/previous-versions/dotnet/articles/…
Abel

8

Wenn es nicht darum geht, den Status beizubehalten (es sind keine Felder oder Eigenschaften erforderlich), ist es immer besser, eine statische Klasse zu verwenden?

Ich würde Ja sagen. Wenn staticSie etwas deklarieren, erklären Sie die Absicht einer zustandslosen Ausführung (dies ist nicht obligatorisch, aber eine Absicht von etwas, das man erwarten würde).

Wenn es eine beträchtliche Anzahl dieser statischen Klassen gibt (z. B. 100 mit jeweils einer Anzahl statischer Methoden), wirkt sich dies negativ auf die Ausführungsleistung oder den Speicherverbrauch im Vergleich zur gleichen Anzahl von Instanzklassen aus?

Denken Sie nicht, es sei denn, Sie sind sicher, dass statische Klassen wirklich stetig sind, denn wenn nicht, ist es einfach, Speicherzuordnungen durcheinander zu bringen und Speicherlecks zu bekommen.

Tritt die Instanzauflösung immer noch auf, wenn das Schlüsselwort [this] verwendet wird, um eine andere Methode innerhalb derselben Instanzklasse aufzurufen?

Ich bin mir über diesen Punkt nicht sicher (dies ist ein reines Implementierungsdetail von CLR), aber denke ja.


Statische Methoden können nicht verspottet werden. Wenn Sie TDD oder nur Unit-Tests durchführen, werden Ihre Tests sehr beeinträchtigt.
Trampster

@ Trampster Warum? Es ist nur ein Stück Logik. Sie können leicht verspotten, was Sie es geben? Um das richtige Verhalten zu bekommen. Und viele statische Methoden sind sowieso private Logikelemente in einer Funktion.
M. Mimpen

@ M.Mimpen, solange Sie es kleinen privaten Stücken überlassen, Ihre Geldstrafe, wenn es eine öffentliche Methode ist und Sie es von anderen Closes verwenden und ändern müssen, was es in Ihrem Test tut, dann stecken Sie fest, Dinge wie Datei-E / A oder Datenbankzugriff oder Netzwerkaufrufe usw., wenn eine statische Methode eingegeben wird, werden nicht mehr spottbar, es sei denn, Sie sagen, Sie fügen der statischen Methode eine verspottbare Abhängigkeit als Parameter hinzu
Trampster

-2

statische Methoden sind schneller, aber weniger OOP. Wenn Sie Entwurfsmuster verwenden, statische Methode, wahrscheinlich schlechter Code, um Geschäftslogik besser zu schreiben, ohne statische, allgemeine Funktionen wie das Lesen von Dateien, WebRequest usw. besser als statisch zu realisieren ... Ihre Fragen sind nicht universell Antworten


16
Sie haben Ihre Behauptungen nicht argumentiert.
Ymajoros

2
@ fjch1997 2 upvoters scheinen anders zu denken (für das, was es wert ist). Das Kommentieren von Abstimmungen wird zum Üben von Stackexchange empfohlen: meta.stackexchange.com/questions/135/…
ymajoros
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.