Bieten versiegelte Klassen wirklich Leistungsvorteile an?

  • Ich bin auf eine Reihe von Optimierungstipps gestoßen, die besagen, dass Sie Ihre Klassen als versiegelt markieren sollten, um zusätzliche Leistungsvorteile zu erhalten.

    Tests zur Überprüfung der Leistungsdifferenz und keine gefunden. Mache ich etwas falsch? Verpasse ich den Fall, dass versiegelte Klassen bessere Ergebnisse liefern?

    Hat jemand Tests ausgeführt und einen Unterschied festgestellt?

    Helfen Sie mir lernen:)

    14 October 2008
    Lance RobertsRuben Steins
9 answers
  • Der JITter verwendet manchmal nicht-virtuelle Aufrufe von Methoden in versiegelten Klassen, da sie nicht weiter erweitert werden können.

    Es gibt komplexe Regeln für das Aufrufen Geben Sie ein, virtual / nonvirtual, und ich kenne sie nicht alle. Daher kann ich sie nicht wirklich umreißen. Wenn Sie jedoch nach versiegelten Klassen und virtuellen Methoden suchen, finden Sie möglicherweise einige Artikel zum Thema.

    Beachten Sie, dass jede Art von Leistungsvorteil, die Sie aus dieser Optimierungsstufe erzielen würden, als letztes Mittel betrachtet werden sollte. Optimieren Sie immer auf der algorithmischen Ebene, bevor Sie die Optimierung auf Codeebene durchführen.

    Hier ist ein Link, der dies erwähnt: Auf dem versiegelten Keyword wandern

    05 August 2008
    Lasse Vågsæther Karlsen
  • Update: Ab .NET Core 2.0 und .NET Desktop 4.7.1 unterstützt die CLR jetzt Devirtualisierung. Es kann Methoden in versiegelten Klassen annehmen und virtuelle Anrufe durch direkte Aufrufe ersetzen. Dies kann auch für nicht versiegelte Klassen geschehen, wenn es herausgefunden werden kann, dass dies sicher ist.

    In einem solchen Fall (eine versiegelte Klasse, die die CLR ansonsten nicht als sicher für die Devirtualisierung erkennen konnte) sollte eine versiegelte Klasse tatsächlich einen Leistungsvorteil bieten.

    Das heißt: Ich denke nicht, dass es sich lohnt, sich über Gedanken zu machen, es sei denn, Sie haben den Code bereits erstellt und festgestellt, dass Sie sich in einem besonders heißen Pfad befinden, der millionenfach aufgerufen wird, oder etwas Ähnliches:

    https://blogs.msdn.microsoft.com/dotnet/2017/06/29/performance-improvements-in-ryujit-in-net-core-and-net -framework /


    Ursprüngliche Antwort:

    Ich habe folgendes gemacht Testprogramm und dekompilierte es dann mit Reflector welcher MSIL-Code ausgegeben wurde.

     public class NormalClass {
        public void WriteIt(string x) {
            Console.WriteLine("NormalClass");
            Console.WriteLine(x);
        }
    }
    
    public sealed class SealedClass {
        public void WriteIt(string x) {
            Console.WriteLine("SealedClass");
            Console.WriteLine(x);
        }
    }
    
    public static void CallNormal() {
        var n = new NormalClass();
        n.WriteIt("a string");
    }
    
    public static void CallSealed() {
        var n = new SealedClass();
        n.WriteIt("a string");
    }
     

    In allen Fällen erstellt der C # -Compiler (in Version 2010 von Visual Studio erstellte Konfiguration) ) gibt eine identische MSIL aus, die wie folgt aussieht:

     L_0000: newobj instance void <NormalClass or SealedClass>::.ctor()
    L_0005: stloc.0 
    L_0006: ldloc.0 
    L_0007: ldstr "a string"
    L_000c: callvirt instance void <NormalClass or SealedClass>::WriteIt(string)
    L_0011: ret 
     

    Der oft zitierte Grund, aus dem die Leute sagen, versiegelt zu sein, bietet Leistung Die Vorteile sind, dass der Compiler weiß, dass die Klasse nicht überschrieben wird, und daher call anstelle von callvirt verwenden kann, da er nicht nach virtuellen Computern suchen muss. Wie oben gezeigt, ist dies jedoch nicht der Fall.

    Mein nächster Gedanke war, dass der JIT-Compiler, obwohl die MSIL identisch ist, die versiegelten Klassen möglicherweise anders behandelt?

    Ich habe einen Release-Build ausgeführt der Visual Studio Debugger und betrachtete die dekompilierte x86-Ausgabe. In beiden Fällen war der x86-Code mit Ausnahme von Klassennamen und Funktionsspeicheradressen (die natürlich unterschiedlich sein müssen) identisch. Hier ist es

    15 August 2017
    Orion Edwards
  • Das Markieren einer Klasse sealed sollte keine Auswirkungen auf die Leistung haben.

    In einigen Fällen muss csc möglicherweise einen Opcode callvirt anstelle von a ausgeben call Opcode. Es scheint jedoch, dass diese Fälle selten sind.

    Und es scheint mir, dass das JIT in der Lage sein sollte, denselben nicht-virtuellen Funktionsaufruf für callvirt auszugeben, für den es zuständig wäre call, wenn bekannt ist, dass die Klasse (noch) keine Unterklassen hat. Wenn nur eine Implementierung der Methode vorhanden ist, ist es nicht sinnvoll, die Adresse aus einer vtable zu laden. Rufen Sie einfach die eine Implementierung direkt auf. In dieser Hinsicht kann die JIT sogar die Funktion einbetten.

    Es ist ein bisschen ein Glücksspiel von Seiten der JIT, denn wenn eine Unterklasse später geladen wird , die JIT muss den Maschinencode wegwerfen, den Code erneut kompilieren und einen echten virtuellen Anruf auslösen. Meine Vermutung ist, dass dies in der Praxis nicht oft der Fall ist.

    (Und ja, VM-Designer verfolgen diese winzigen Leistungsgewinne wirklich aggressiv.)

    20 November 2009
    Jason Orendorffron
  • & lt; Off-Topic-Rant & gt;

    Ich lasse versiegelte Klassen. Selbst wenn die Leistungsvorteile erstaunlich sind (was ich bezweifle), zerstören sie das objektorientierte Modell, indem sie die Wiederverwendung durch Vererbung verhindern. Beispielsweise ist die Thread-Klasse versiegelt. Ich sehe zwar, dass man möchte, dass Threads so effizient wie möglich sind, aber ich kann mir auch Szenarien vorstellen, in denen die Möglichkeit, Thread zu subklassieren, große Vorteile hätte. Klassenautoren, wenn Sie Ihre -Siegelung abschließen müssen Klassen aus Gründen der "Leistung": Bitte geben Sie mindestens ein Interface an, damit wir nicht überall einpacken und ersetzen müssen, wenn wir eine Funktion benötigen, die Sie vergessen haben.

    Beispiel: SafeThread musste die Thread-Klasse da einpacken Thread ist versiegelt und es gibt keine IThread-Schnittstelle. SafeThread fängt automatisch nicht behandelte Ausnahmen in Threads ab, was in der Thread-Klasse vollständig fehlt. [und nein, die nicht behandelten Ausnahmeereignisse nehmen nicht nicht behandelte Ausnahmen in sekundären Threads auf.]

    & lt; / off-topic-rant & gt;

    15 October 2008
    Steven A. Lowe
  • Ich halte "versiegelte" Klassen für den Normalfall, und ich habe IMMER einen Grund, das Schlüsselwort "Sealed" wegzulassen.

    Die wichtigsten Gründe für mich sind:

    a) Bessere Kompilierzeitprüfungen (das Umsetzen auf nicht implementierte Schnittstellen wird zur Kompilierzeit erkannt, nicht nur zur Laufzeit)

    und, der Hauptgrund:

    b) Der Missbrauch meiner Klassen ist auf diese Weise nicht möglich.

    Ich wünschte, Microsoft hätte "versiegelt" gemacht "der Standard, nicht" nicht versiegelt ".

    03 August 2010
    Turing Complete
  • Versiegelte Klassen sollten eine Leistungsverbesserung bieten. Da eine versiegelte Klasse nicht abgeleitet werden kann, können beliebige virtuelle Mitglieder in nicht virtuelle Mitglieder umgewandelt werden.

    Natürlich sprechen wir hier von wirklich kleinen Errungenschaften. Ich würde eine Klasse nicht als versiegelt markieren, um eine Leistungsverbesserung zu erreichen, es sei denn, das Profiling hat gezeigt, dass dies ein Problem darstellt.

    05 August 2008
    mrdenny
  • versiegelte Klassen werden mindestens um ein kleines bisschen schneller sein, können aber manchmal auch schneller sein ... wenn der JIT-Optimierer Inline-Aufrufe verwenden kann, die ansonsten virtuelle Aufrufe gewesen wären. Wo häufig genannte Methoden vorhanden sind, die klein genug sind, um inline dargestellt zu werden, sollten Sie die Klasse unbedingt versiegeln.

    Der beste Grund, eine Klasse zu versiegeln, ist jedoch zu sagen: "Ich habe nicht Wenn Sie davon ausgehen, dass dies vererbt wird, werde ich Sie nicht verbrennen lassen, wenn Sie davon ausgehen, dass dies so ist, und ich werde mich nicht selbst verbrennen, wenn ich in eine Implementierung eingeschlossen werde, weil ich Sie davon ableiten lasse it. "

    Ich weiß, dass einige hier gesagt haben, sie hassen versiegelte Klassen, weil sie die Möglichkeit haben, von irgendetwas abzuleiten ... aber das ist OFTEN nicht die haltbarste Wahl ... denn wenn Sie eine Klasse der Ableitung aussetzen, sind Sie viel mehr gebunden, als das alles nicht zu zeigen. Es ist ähnlich zu sagen "Ich hasse Klassen, die private Mitglieder haben ... Ich kann die Klasse oft nicht machen lassen, was ich will, weil ich keinen Zugang habe." Einkapselung ist wichtig ... Versiegelung ist eine Form der Einkapselung.

    01 October 2011
    Brian Kennedy
  • @Vaibhav, welche Art von Tests haben Sie ausgeführt, um die Leistung zu messen?

    Ich denke, man müsste Rotor , um die CLI zu untersuchen und zu verstehen, wie eine versiegelte Klasse die Leistung verbessern könnte.

    SSCLI (Rotor)
    SSCLI: Gemeinsame Quellinfrastruktur für gemeinsame Sprachen

    Die Infrastruktur für häufig verwendete Sprachen ( CLI) ist der ECMA-Standard, der den Kern des .NET-Frameworks beschreibt. Die Shared Source CLI (SSCLI), auch als Rotor bezeichnet, ist ein komprimiertes Archiv des Quellcodes für eine funktionierende Implementierung der ECMA-CLI und der Spezifikation der ECMA C # -Sprache , Technologien im Herzen von .NET .

    05 August 2008
    Sathya
  • Führen Sie diesen Code aus und Sie sehen, dass versiegelte Klassen zweimal schneller sind:

     class Program
    {
        static void Main(string[] args)
        {
            Console.ReadLine();
    
            var watch = new Stopwatch();
            watch.Start();
            for (int i = 0; i < 10000000; i++)
            {
                new SealedClass().GetName();
            }
            watch.Stop();
            Console.WriteLine("Sealed class : {0}", watch.Elapsed.ToString());
    
            watch.Start();
            for (int i = 0; i < 10000000; i++)
            {
                new NonSealedClass().GetName();
            }
            watch.Stop();
            Console.WriteLine("NonSealed class : {0}", watch.Elapsed.ToString());
    
            Console.ReadKey();
        }
    }
    
    sealed class SealedClass
    {
        public string GetName()
        {
            return "SealedClass";
        }
    }
    
    class NonSealedClass
    {
        public string GetName()
        {
            return "NonSealedClass";
        }
    }
     

    Ausgabe: Versiegelte Klasse: 00: 00: 00.1897568 Nicht verschweißte Klasse: 00: 00: 00.3826678

    26 November 2009
    RuslanG