.NET 4.6 bringt einige CLR-Funktionen mit sich, die sich auf Leistungsverbesserungen beziehen. Einige dieser Funktionen werden automatisch wirksam, während andere, wie SIMD und Async Local Storage, Änderungen an der Art und Weise erfordern, wie Anwendungen geschrieben werden.
Das Mono-Team war schon immer stolz auf die Unterstützung von SIMD, der Single-Instruction-Stream-Multiple-Data-Stream-Funktion. SIMD ist ein CPU-Befehlssatz, der den gleichen Vorgang für bis zu 8 Werte gleichzeitig ausführen kann. Mit der Einführung von .NET CLR Version 4.6 können Windows-Entwickler diese Funktion endlich nutzen.
Um die Wirkung von SIMD tatsächlich zu beobachten, können Sie sich auf dieses Beispiel beziehen. Angenommen, Sie müssen zwei Arrays in der Form c[i] = a[i] + b[i] hinzufügen, um ein drittes Array zu erhalten. Durch die Verwendung von SIMD können Sie Code auf folgende Weise schreiben:
for (int i = 0; i < size; i += Vector.Count) { Vectorv = new Vector(A,i) + new Vector(B,i); v.CopyTo(C,i); }
Beachten Sie, wie diese Schleife um den Wert von Vector
Diese Methode erscheint etwas umständlich, daher bietet Microsoft auch eine Reihe von Hilfsklassen an, darunter:
Matrix3x2-Struktur
Matrix4x4-Struktur
Flugzeugstruktur
Quaternionstruktur
Vektorklasse
Vektor(T)-Struktur
Vector2-Struktur
Vector3-Struktur
Vector4-Struktur
Ich fürchte, die meisten Entwickler wissen das nicht: .NET lädt oft dieselbe Assembly zweimal. Voraussetzung hierfür ist, dass .NET zunächst die IL-Version einer Assembly und anschließend die NGEN-Version (d. h. die vorkompilierte Version) derselben Assembly lädt. Dieser Ansatz stellt eine erhebliche Verschwendung von physischem Speicher dar, insbesondere bei großen 32-Bit-Anwendungen wie Visual Studio.
Sobald die CLR in .NET 4.6 die NGEN-Version einer Assembly lädt, löscht sie automatisch den von der entsprechenden IL-Version belegten Speicher.
Zuvor haben wir den in .NET 4.0 eingeführten Garbage Collection-Verzögerungsmodus besprochen. Obwohl diese Methode viel zuverlässiger ist, als den GC für einen bestimmten Zeitraum vollständig anzuhalten, reicht sie für viele GC-Szenarien immer noch nicht aus.
In .NET 4.6 können Sie den Garbage Collector auf komplexere Weise vorübergehend anhalten. Mit der neuen TryStartNoGCRegion-Methode können Sie angeben, wie viel Speicher im Heap für kleine und große Objekte benötigt wird.
Wenn nicht genügend Speicher vorhanden ist, gibt die Laufzeit den Wert „false“ zurück oder stoppt die Ausführung, bis durch die GC-Reinigung genügend Speicher verfügbar ist. Sie können dieses Verhalten steuern, indem Sie ein Flag an TryStartNoGCRegion übergeben. Wenn Sie erfolgreich einen GC-freien Bereich betreten (GC ist bis zum Ende des Prozesses nicht zulässig), muss am Ende des Prozesses die Methode EndNoGCRegion aufgerufen werden.
In der offiziellen Dokumentation wird nicht angegeben, ob diese Methode Thread-sicher ist. Angesichts des Funktionsprinzips von GC sollten Sie jedoch vermeiden, dass zwei Prozesse gleichzeitig versuchen, den GC-Status zu ändern.
Eine weitere Verbesserung des GC ist die Art und Weise, wie er mit angehefteten Objekten umgeht (d. h. Objekte, die nach der Zuweisung nicht verschoben werden können). Obwohl dieser Aspekt in der Dokumentation etwas vage beschrieben wird, werden beim Fixieren der Position eines Objekts normalerweise auch die Positionen der benachbarten Objekte fixiert. Rich Lander schrieb in dem Artikel:
Der GC verarbeitet angeheftete Objekte optimierter, sodass der GC den Speicher um die angehefteten Objekte effektiver komprimieren kann. Bei umfangreichen Anwendungen, die eine große Anzahl von Pins verwenden, wird diese Änderung die Leistung der Anwendung erheblich verbessern.
GC zeige auch eine bessere Intelligenz bei der Nutzung des Gedächtnisses in früheren Generationen, schrieb Rich weiter:
Die Art und Weise, wie Objekte der Generation 1 zu Objekten der Generation 2 hochgestuft werden, wurde ebenfalls verbessert, um den Speicher effizienter zu nutzen. Bevor einer Generation neuer Speicherplatz zugewiesen wird, versucht der GC zunächst, den verfügbaren Speicherplatz zu nutzen. Gleichzeitig wird beim Erstellen von Objekten unter Nutzung des verfügbaren Speicherplatzbereichs ein neuer Algorithmus verwendet, sodass die Größe des neu zugewiesenen Speicherplatzes näher an der Größe des Objekts liegt als zuvor.
Die letzte Verbesserung steht nicht in direktem Zusammenhang mit der Leistung, kann aber dennoch durch effektive Nutzung Optimierungsergebnisse erzielen. In den Tagen, bevor asynchrone APIs populär wurden, konnten Entwickler Thread Local Storage (TLS) nutzen, um Informationen zwischenzuspeichern. TLS verhält sich wie ein globales Objekt für einen bestimmten Thread, was bedeutet, dass Sie direkt auf Kontextinformationen zugreifen und diese zwischenspeichern können, ohne explizit ein Kontextobjekt übergeben zu müssen.
Im Async/Warten-Modus wird der lokale Thread-Speicher unbrauchbar. Denn jedes Mal, wenn „await“ aufgerufen wird, ist es möglich, zu einem anderen Thread zu springen. Und selbst wenn es Ihnen gelingt, diese Situation zu vermeiden, könnte anderer Code zu Ihrem Thread springen und die Informationen in TLS stören.
Die neue Version von .NET führt den Asynchronous Local Storage (ALS)-Mechanismus ein, um dieses Problem zu lösen. ALS entspricht semantisch dem Thread-Local-Storage, kann jedoch mit dem Aufruf vonwait entsprechende Sprünge durchführen. Diese Funktion wird über die generische Klasse AsyncLocal implementiert, die intern das CallContext-Objekt aufruft, um Daten zu speichern.
Das obige ist der detaillierte Inhalt vonEin detaillierter Blick auf Leistungsverbesserungen in .NET. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!