Ich habe es satt zu hören, dass Leute empfehlen, nur einen Thread pro Prozessor zu verwenden, während viele Programme bis zu 100 pro Prozess verwenden! nehmen Sie zum Beispiel einige gängige Programme
vb.net ide uses about 25 thread when not debugging
System uses about 100
chrome uses about 19
Avira uses more than about 50
Jedes Mal, wenn ich eine Thread-bezogene Frage stelle, werde ich fast jedes Mal daran erinnert, dass ich nicht mehr als einen Thread pro Prozessor verwenden sollte und alle oben genannten Programme mit einem einzigen Prozessor mein System ruinieren.
Antworten:
Möglicherweise in HPC, wo Sie maximale Effizienz wollen - aber sonst das Dümmste, was ich heute gehört habe!
Sie sollten die Anzahl der Threads verwenden, die für das Design des Programms geeignet sind und dennoch eine akzeptable Leistung bieten.
Für einen Webserver kann es sinnvoll sein, für jede eingehende Verbindung einen Thread auszulösen (obwohl es für sehr stark ausgelastete Server bessere Möglichkeiten gibt).
Für eine Idee ist es nicht unangemessen, dass jedes Tool in einem eigenen Thread ausgeführt wird. Ich vermute, dass viele der Threads, die für die .NET-IDE gemeldet wurden, Dinge wie Protokollierung und E / A-Aufgaben sind, die in ihren eigenen Threads gestartet werden, damit sie weiterhin nicht blockiert werden können.
quelle
Der Hinweis "Ein Thread pro Kern" gilt, wenn der Zweck die Geschwindigkeit durch parallele Ausführung ist.
Ein völlig anderer und ebenso gültiger Grund ist die Einfachheit des Codes, wenn er auf unvorhersehbare Ereignisse reagieren muss. Wenn ein Programm also 100 Sockets abhören muss und jedem seine volle Aufmerksamkeit zu widmen scheint, ist dies eine perfekte Verwendung für das Threading. Ein weiteres Beispiel ist eine Benutzeroberfläche, in der ein Thread Benutzeroberflächenereignisse verarbeitet, während ein anderer die Hintergrundverarbeitung ausführt.
quelle
Sie möchten einen Thread für jede Berechnung, der mit anderen Raten als andere Berechnungen ablaufen kann.
Für parallele CPU-gebundene Berechnungen, die in großen Arbeitsblöcken ausgeführt werden, benötigen Sie im Allgemeinen einen Thread pro CPU, da mehr Threads nicht helfen und nur einen Scheduler-Overhead verursachen, wenn sie alle ausgelastet sind. Wenn die Arbeitsblöcke zeitlich unregelmäßig groß sind oder zur Laufzeit dynamisch generiert werden (häufig bei der Verarbeitung großer komplexer Datenstrukturen), möchten Sie diese Blöcke möglicherweise an viele Threads anhängen, sodass ein Scheduler immer über große Datenmengen verfügt Legen Sie fest, ob nach Abschluss eines Arbeitsblocks alle CPUs ausgelastet sein sollen.
Für E / A-gebundene Berechnungen benötigen Sie im Allgemeinen einen Thread für jeden unabhängigen E / A-"Kanal", da diese mit unterschiedlichen Raten kommunizieren und Threads, die auf dem Kanal blockiert sind, andere Threads nicht daran hindern, Fortschritte zu erzielen.
quelle
Die Faustregel für Threads lautet: Sie möchten, dass mindestens ein "aktiver" Worker-Thread für jede auf dem Computer verfügbare "Ausführungseinheit" auf dem Computer vorhanden ist (die Befehle können sofort ausgeführt werden, wenn die CPU-Zeit abgelaufen ist). Eine "Ausführungseinheit" ist ein logischer Befehlsprozessor, sodass ein Quad-Chip-Quad-Core-Xeon-Hyperthread-Server 32 EUs (4 Chips, 4 Kerne pro Chip, jeder Hyperthread) aufweist. Ihr durchschnittlicher Core i7 hätte 8.
Ein Thread pro EU nutzt die CPU-Leistung voll aus, vorausgesetzt, die Threads sind immer in Betrieb. Dies ist fast nie der Fall, da Threads Zugriff auf nicht zwischengespeicherten Speicher, die Festplatte, Netzwerkports usw. benötigen, auf die sie warten müssen, und für deren Ausführung keine aktive CPU-Aufmerksamkeit erforderlich ist. Auf diese Weise können Sie die Gesamteffizienz weiter steigern, wenn sich mehr Threads in der Warteschlange befinden und nur noch wenige verfügbar sind. Dies ist mit Kosten verbunden. Wenn eine CPU einen Thread wechselt, muss sie die Register, den Ausführungszeiger und andere Statusinformationen des Threads zwischenspeichern, die normalerweise im Innersten einer EU gespeichert sind und auf die sehr schnell zugegriffen werden kann, damit andere EUs in diesem CPU-Chip darauf zugreifen können. Es erfordert auch Threads im Betriebssystem, um zu entscheiden, zu welchem Thread gewechselt werden soll. Schließlich, wenn eine EU Themen wechselt, es verliert die Leistungsgewinne des Pipelining, das die meisten Prozessorarchitekturen verwenden; Es muss die Pipeline leeren, bevor Threads gewechselt werden. Aber da all dies im Durchschnitt immer noch viel weniger Zeit in Anspruch nimmt als nur darauf zu warten, dass die Festplatte oder sogar der Arbeitsspeicher mit Informationen versorgt wird, sind die Kosten wert.
Wenn Sie jedoch die doppelte Anzahl "aktiver" Threads als EUs überschreiten, verwendet das Betriebssystem im Allgemeinen mehr Zeitplanungs-Threads der EUs, und die EUs verbringen mehr Zeit mit dem Umschalten zwischen diesen Threads als mit dem Ausführen aktiver Threads von Programmen. Dies ist der Punkt von Größenunterschieden; Es dauert länger, bis ein Multithread-Algorithmus ausgeführt wird, wenn Sie an dieser Stelle einen zusätzlichen Thread hinzufügen.
Insgesamt möchten Sie also mindestens so viele Threads in Ihrem Programm beibehalten, wie EUs auf dem Computer vorhanden sind, aber Sie möchten vermeiden, dass mehr als die doppelte Anzahl an Threads vorhanden ist, die nicht warten oder schlafen.
quelle
Sie sollten einen Thread für Folgendes verwenden:
Jeder Prozessor, den Sie beschäftigen müssen.
Jedes E / A, das Sie sinnvollerweise gleichzeitig anhalten können, kann nicht blockierungsfrei ausgeführt werden. (Liest beispielsweise von einer lokalen Festplatte.)
Jede Aufgabe, die einen dedizierten Thread erfordert, z. B. das Aufrufen einer Bibliothek ohne nicht blockierende Schnittstelle oder wenn nicht blockierende Schnittstellen nicht geeignet sind. Dies umfasst Aufgaben wie das Überwachen der Systemuhr, das Auslösen von Timern usw.
Ein paar zusätzliche Maßnahmen zum Schutz vor unerwarteten Blockierungen wie Seitenfehlern.
Ein paar zusätzliche Maßnahmen zum Schutz vor erwarteten Blockierungen, die es nicht wert sind, optimiert zu werden, z. B. in unkritischem Code. (Wenn Sie beispielsweise sehr selten eine DNS-Anforderung ausführen müssen, lohnt es sich wahrscheinlich nicht, DNS-Anforderungen asynchron auszuführen. Erstellen Sie einfach ein paar zusätzliche Threads, und vereinfachen Sie Ihr Leben.)
Wenn Sie die Regel "Ein Thread pro Prozessor" befolgen, ist der gesamte Code leistungskritisch. Jeder Code, der aus irgendeinem Grund blockiert, bedeutet, dass Ihr Prozess diesen Prozessor nicht verwenden kann. Das macht das Programmieren ohne guten Grund sehr viel schwieriger.
quelle
Sie können entweder Prozesse und Threads erzeugen, um die Verwendung eines Multicore \ Multiprozessorsystems für ein einzelnes Programm zu ermöglichen. In diesem Fall profitieren Sie (zumindest für das einzelne Programm) nicht davon, mehr Threads \ Prozesse als Kerne zu haben.
Oder Sie können Routinen haben, die nach einem Ereignis suchen, das normalerweise die weitere Ausführung blockiert. Statt die CPU mit einem Polling zu verbinden, können Sie stattdessen einen Thread erstellen, der sich im Leerlauf befindet, bis das entsprechende Ereignis ihn aufweckt. Diese Methode wird sehr häufig in Webservern und GUI-Ereigniswarteschlangen verwendet. Die meisten Programme möchten eine Art zentralen Datenspeicher haben (auch wenn der Programmausführungscode), auf den alle Threads zugreifen können. Ich denke, deshalb verwenden sie Threading über Prozesse.
quelle
Die Anwendungen , die Sie erwähnen , sind selten laufen alle diese zehn Threads gleichzeitig. Die meisten von ihnen sitzen einfach da, weil sie in einem Thread-Pool sind . Die App sendet verschiedene Aufgaben an eine Warteschlange, die von Threads im Thread-Pool gelöscht wird.
Warum ist der Pool dann so groß? Da Threads häufig auf andere Ressourcen wie Festplatte, Netzwerk, Benutzer, einen anderen Thread usw. warten müssen. Während ein Thread wartet, sollten andere Threads ausgeführt werden, um den Prozessor voll auszunutzen. Die richtige Dimensionierung des Pools ist jedoch schwierig. Bei zu wenigen Threads geht die Leistung verloren, da der Prozessor beim Warten auf etwas nicht voll ausgelastet ist. Zu viele Threads, und Sie verlieren die Leistung, weil Sie zwischen ihnen wechseln.
quelle