Ich habe eine .NET-Anwendung, von der ich erwarte, dass 5 lange laufende Threads einschließlich des Hauptthreads laufen. Ich kann sehen, dass in der Tat 4 Threads in der Codebasis aktualisiert werden, und ich glaube, dass es nirgendwo direkte (z. B. Arbeitsaufgaben-Warteschlangen / Aufgaben) oder indirekte (z. B. Timer) Verwendung des ThreadPools gibt. Zumindest kann ich nichts finden.
Das Ausführen der App unter Systemmonitor zeigt, dass die Anzahl der erkannten Threads konstant bei 5 bleibt (wie ich erwarten würde), aber die Anzahl der physischen Threads schwankt im Laufe von etwa einer Stunde zwischen 70 und 120!
Weiß jemand, warum es so viele unbenutzte (soweit ich es sagen kann) physische Threads gibt? Und warum schwankt diese Zahl?
Ich kann keine Dokumentation finden, die dieses Verhalten erklären würde, also denke ich, dass der ThreadPool sich selbst ausgleicht, um sich ändernden Umweltfaktoren wie freiem Speicher und Ressourcenkonflikten Rechnung zu tragen, aber die Zahlen hier scheinen übertrieben.
Aktualisieren
Ein leitender Support-Techniker bei Microsoft hat bestätigt, dass der verwendete physische Thread-Zähler trotz der ungeraden Formulierung in MSDN definitiv nur Threads für den aktuellen Prozess meldet. Wenn eine Antwort darauf hindeutet, dass dies nicht der Fall ist, muss auf eine definitive Quelle hingewiesen werden.
Beide ThreadPools und der GC erstellen Threads. Es gibt einen normalen (oder "worker") Thread-Pool und einen IO threapool . Der normale Threadpool weist neue Threads zu, die er benötigt, um den Threadpool ansprechend zu halten. Es sollte sofort einen Thread pro CPU erstellen und wahrscheinlich einen Thread pro Sekunde danach bis zur minimalen Anzahl von Threads. Siehe ThreadPool.GetMinThreads
für die Mindestanzahl von Worker-Threads des Worker-Threads Pool wird erstellt. Siehe ThreadPool.GetAvailableThreads
für die Nummer von "aktiven" Worker-Threads im Worker-Thread-Pool. Wenn Sie lange laufende Threads mit Worker-Thread-Pool-Threads verwenden, wird dies glauben, dass der Thread verwendet wird, und einen anderen zuweisen, um zukünftige Anforderungen zu bedienen.
Es gibt auch eine maximale Anzahl von Threads im Pool. Wenn also Threads in den Pool zurückverteilt werden, kann der Pool einige davon abstoßen, um wieder auf ein # zu kommen, das am besten ist.
Es gibt auch einen Finalizer-Thread.
Es gibt wahrscheinlich andere, die undokumentiert sind oder aus einer Bibliothek stammen, die Sie verwenden.
Ich denke, ein Teil des Problems ist Verwirrung über "erkannte Threads" und "physische Threads" und "unbenutzte Threads". Erkannte Threads sind dokumentiert als (Hervorhebung von mir)
Diese Threads sind einem entsprechenden verwalteten Thread-Objekt zugeordnet. Die Laufzeitumgebung erstellt diese Threads nicht , aber sie wurden mindestens einmal innerhalb der Laufzeit ausgeführt.
Physische Threads sind dokumentiert als (Hervorhebung von mir)
native Betriebssystem-Threads , die von der Common Language Runtime erstellt und verwaltet werden , um als zugrunde liegende Threads für verwaltete Thread-Objekte zu fungieren
Ich vermute, dass der Begriff "unbenutzte Threads" von @JRoughan sich auf "physische Threads" bezieht - diejenigen, die nicht "erkannt" werden. Was nicht wirklich bedeutet, dass sie ungenutzt sind, sie sind einfach nicht im anerkannten Counter. Wie die Dokumentation darauf hinweist, werden "physische Threads" von der Laufzeit erstellt, und ich glaube nicht, dass Sie von einem dieser Zähler unterscheiden können, ob ein Thread "verwendet" oder "nicht verwendet" ist. abhängig davon, was @JRoughan mit "unbenutzt" meint.
Solche Dinge haben keine einfache Antwort. Sie müssen entweder unter einem Debugger oder ETW-Traces untersuchen.
Mit ETW-Traces können Sie Ereignisse für jede Thread-Erstellung / -Zerstörung abrufen, optional mit Aufruf-Stack.
CLR selbst könnte Threads für sich selbst erstellen (z. B. GC-Threads, Hintergrund-GC-Threads, Multicore-JIT-Thread), Thread-Pool-Threads, IO-Threads, Timer-Thread. Es gibt eine andere Art von Thread: Gate-Thread.
Normalerweise können Sie die Verwendung vom symbolischen Namen des Thread-Procs unterscheiden, sobald die Symbole aufgelöst sind.
Verwenden Sie für die ETW-Analyse PerfView von Microsoft.
Prüft die Anwendung, die Sie in der Leistung testen, eine eigenständige .net-Anwendung oder eine Anwendung unter IIS? Wenn es sich um eine Standalone-Anwendung handelt, fügen Sie wahrscheinlich zusätzlichen lib / code hinzu, um den performace-Monitor zu verwenden. Es kann Threads erstellen.
Sie können den Process Explorer von Sysinternals verwenden, um Threads in Ihrem Prozess zu beobachten. Sie können sehen, welche Methode in welchem Modul die Threads gestartet hat.
Wir können natürlich nur spekulieren. Meine eigene Wette wäre über In-Process-COM-Server . Diese und ihre zugehörigen Threads können erstellt werden, wenn Sie Klassen verwenden, die COM-Schnittstellen umschließen, z. B. für Verzeichnisdienste oder WMI. Da sie mit systemeigenem Code erstellt werden (obwohl sie in einen Dotnet-Code eingebettet sind), werden sie nicht als verwaltete Threads erkannt.
Tags und Links .net c# multithreading