Verstehen Sie den .Net CLR-Thread-Pool

Im .NET Framework ist die CLR dafür verantwortlich, Ressourcen für die Ausführung von Anwendungen bereitzustellen. Insbesondere bestimmt der CLR-Thread-Pool, wann Threads hinzugefügt oder entfernt werden sollen. Wenn Sie wissen, wie dies funktioniert, können Sie bestimmen, wie Sie Ihre ASP.Net-Anwendung für eine optimale Leistung konfigurieren.

Der CLR-Thread-Pool enthält zwei Arten von Threads: die Worker-Threads und den E / A-Abschlussport oder IOCP-Threads. Das bedeutet, dass Ihr ASP.Net-Worker-Prozess tatsächlich zwei Thread-Pools enthält: den Worker-Thread-Pool und den IOCP-Thread-Pool. Natürlich haben diese Pools unterschiedliche Zwecke.

Wenn Sie Methoden verwenden , wie Task.Run, TaskFactory.StartNewund ThreadPool.QueueUserWorkItemnimmt die Laufzeit Vorteil der Worker - Threads für die Verarbeitung. Wenn Sie in Ihrer Anwendung asynchrone E / A-Aufrufe ausführen oder Ihre Anwendung auf das Dateisystem, Datenbanken, Webdienste usw. zugreift, verwendet die Laufzeit IOCP-Threads. Beachten Sie auch, dass jede Anwendungsdomäne einen eigenen Thread-Pool hat.

Schauen wir uns genauer an, wie diese Threads im .NET Framework erstellt und entfernt werden. 

Strategien zur Fadeninjektion

Der .NET-Thread-Pool beginnt mit dem Einfügen neuer Threads, wenn die Anzahl der ausgelasteten Threads der Anzahl der konfigurierten Mindest-Threads im Thread-Pool entspricht. Der Standardwert der Minimaleinstellung, die die minimale Anzahl an ist  sowohl  Arbeiter und IOCP Threads, wird durch die Anzahl von Prozessoren in dem System bestimmt. Wenn Ihr System also über vier Kerne verfügt, verfügen Sie standardmäßig über vier Worker-Threads und vier IOCP-Threads. 

Der .Net-Thread-Pool fügt dann bei Bedarf zusätzliche Worker-Threads ein, wenn vorhandene Threads verwendet werden und noch Arbeit zu erledigen ist. Aus dem gleichen Grund beginnt der Thread-Pool, Threads zu entfernen, wenn die Nachfrage nach Ressourcen sinkt. 

Wenn Sie das folgende Codefragment ausführen, werden die Anzahl der logischen Prozessoren in Ihrem System und die Mindestanzahl der verfügbaren Worker- und IOCP-Threads angezeigt.

statische Leere Main (string [] args)

{

    int MinimumWorkerThreadCount, MinimumIOCThreadCount;

      int LogicProcessorCount = System.Environment.ProcessorCount;

      ThreadPool.GetMinThreads (aus MinimumWorkerThreadCount, aus MinimumIOCThreadCount);

      Console.WriteLine ("Anzahl der Prozessoren:" + LogicProcessorCount);

     Console.WriteLine („Mindestanzahl an Worker-Threads:“ + MinimumWorkerThreadCount);

      Console.WriteLine („Mindestanzahl an IOCP-Threads:“ + MinimumIOCThreadCount);

      Console.Read ();

}}

Der .Net-Thread-Pool verwaltet Threads mithilfe seiner integrierten Heuristik. Die angewandten Strategien umfassen die Vermeidung von Hunger und einen Algorithmus zum Bergsteigen. Im ersteren Fall fügt der .NET-Thread-Pool weiterhin Arbeitsthreads hinzu, wenn für die in der Warteschlange befindlichen Elemente kein sichtbarer Fortschritt vorliegt. Im letzteren Fall versucht der .Net-Thread-Pool, den Durchsatz mit möglichst wenigen Threads zu maximieren.

Der .Net-Thread-Pool injiziert oder entfernt Threads in Intervallen von 500 Millisekunden oder wenn ein Thread frei wird, je nachdem, was zuerst eintritt. Basierend auf dem zur Laufzeit verfügbaren Feedback entfernt der .Net-Thread-Pool nun entweder Threads oder fügt Threads hinzu, um den Durchsatz zu maximieren. Wenn das Hinzufügen eines Threads den Durchsatz nicht erhöht, wird ein Thread entfernt. Dies ist die Bergsteigertechnik der CLR in Aktion.

Angenommen, Sie führen Ihre ASP.Net-Anwendung auf IIS aus und Ihr Webserver verfügt über insgesamt vier CPUs. Angenommen, zu einem bestimmten Zeitpunkt müssen 24 Anforderungen verarbeitet werden. Standardmäßig erstellt die Laufzeit vier Threads, die für die Bearbeitung der ersten vier Anforderungen verfügbar sind. Da bis zum Ablauf von 500 Millisekunden keine zusätzlichen Threads hinzugefügt werden, müssen die anderen 20 Anforderungen in der Warteschlange warten. Nach Ablauf von 500 Millisekunden wird ein neuer Thread erstellt.

Wie Sie sehen können, dauert es viele 500-ms-Intervalle, um die Arbeitslast nachzuholen. Dies ist ein guter Grund für die Verwendung der asynchronen Programmierung. Bei der asynchronen Programmierung werden Threads nicht blockiert, während Anforderungen verarbeitet werden, sodass die vier Threads fast sofort freigegeben werden. 

Empfohlene Thread-Einstellungen

Angesichts der Funktionsweise des .Net-Thread-Pools und der bisher besprochenen Informationen wird dringend empfohlen, den Mindestkonfigurationswert - den Standardwert - sowohl für Worker- als auch für IOCP-Threads zu ändern. Um dies in ASP.Net zu tun, sollten Sie die minWorkerThreadsund minIoThreadsKonfigurationseinstellungen unter dem Konfigurationselement in der Datei machine.config in Ihrem System ändern.

           minIoThreads = "Geben Sie hier Ihren gewünschten Wert ein" />

Sie können die Mindestkonfigurationswerte für Worker- und IOCP-Threads auf einen beliebigen Wert zwischen eins und 50 festlegen. Ein guter Ansatz besteht darin, einen Prozessspeicherauszug im Benutzermodus des IIS-Worker-Prozesses (W3wp.exe) zu erstellen und dann den !threadpoolBefehl zum Melden des zu verwenden Gesamtzahl der Worker-Threads. Wenn Sie diesen Wert kennen, teilen Sie ihn einfach durch die Anzahl der Prozessorkerne auf Ihrem System, um die Mindesteinstellungen für Worker und IOCP-Thread zu ermitteln. Wenn beispielsweise die Gesamtzahl der Worker-Threads 100 beträgt und Sie vier Prozessoren in Ihrem System haben, können Sie die Mindestwerte für Worker- und IOCP-Threads auf 25 festlegen.

Um die Standard-Mindest-Thread-Einstellungen außerhalb von ASP.Net zu ändern, können Sie die ThreadPool.SetMinThreads()Methode verwenden.

Mit dem Ziel einer besseren Thread-Verwaltung und einer verbesserten Leistung wurde der CLR-Thread-Pool mit jeder Version der CLR verbessert. Mit .Net Framework 4 hat die CLR beispielsweise Thread-Diebstahlalgorithmen und Unterstützung für Parallelität und Parallelität erhalten. Mit jeder neuen Version der CLR wird der .Net-Thread-Pool intelligenter, wenn es darum geht, den Durchsatz zu optimieren, indem Threads nach Bedarf erstellt und zerstört werden. In der Zwischenzeit sollten Sie mit verschiedenen Mindest-Thread-Einstellungen experimentieren, um die beste Leistung Ihrer .NET-Anwendung zu erzielen.