Ich schreibe einen Server und sende jede Aktion von in einen separaten Thread, wenn die Anfrage empfangen wird. Ich mache das, weil fast jede Anfrage eine Datenbankabfrage macht. Ich verwende eine Threadpool-Bibliothek, um die Konstruktion / Zerstörung von Threads zu reduzieren.
Meine Frage ist: Was ist ein guter Grenzwert für solche E / A-Threads? Ich weiß, es wäre nur eine grobe Schätzung, aber sprechen wir über Hunderte? Tausende?
Wie würde ich herausfinden, wie hoch dieser Grenzwert sein würde?
BEARBEITEN:
Vielen Dank für Ihre Antworten. Es scheint, als müsste ich es nur testen, um meine Obergrenze für die Fadenzahl herauszufinden. Die Frage ist jedoch: Woher weiß ich, dass ich diese Decke erreicht habe? Was genau soll ich messen?
Antworten:
Einige Leute würden sagen, dass zwei Threads zu viele sind - ich bin nicht ganz in diesem Lager :-)
Hier ist mein Rat: Messen, nicht raten. Ein Vorschlag ist, es konfigurierbar zu machen und es zunächst auf 100 zu setzen, dann Ihre Software für die Wildnis freizugeben und zu überwachen, was passiert.
Wenn Ihre Thread-Nutzung bei 3 liegt, ist 100 zu viel. Wenn es den größten Teil des Tages bei 100 bleibt, erhöhen Sie es auf 200 und sehen Sie, was passiert.
Sie könnten Ihren Code selbst die Nutzung überwachen lassen und die Konfiguration für den nächsten Start anpassen, aber das ist wahrscheinlich übertrieben.
Zur Klarstellung und Ausarbeitung:
Ich befürworte nicht, Ihr eigenes Thread-Pooling-Subsystem zu rollen. Verwenden Sie auf jeden Fall das, das Sie haben. Da Sie jedoch nach einem guten Grenzwert für Threads gefragt haben, gehe ich davon aus, dass Ihre Thread-Pool-Implementierung die maximale Anzahl erstellter Threads begrenzen kann (was eine gute Sache ist).
Ich habe Pooling-Code für Thread- und Datenbankverbindungen geschrieben und sie haben die folgenden Funktionen (von denen ich glaube, dass sie für die Leistung wesentlich sind):
Der erste legt eine Basislinie für die Mindestleistung in Bezug auf den Thread-Pool-Client fest (diese Anzahl von Threads steht immer zur Verwendung zur Verfügung). Mit der zweiten Option wird die Ressourcennutzung durch aktive Threads eingeschränkt. Mit dem dritten Schritt kehren Sie in ruhigen Zeiten zur Grundlinie zurück, um den Ressourcenverbrauch zu minimieren.
Sie müssen die Ressourcennutzung durch nicht verwendete Threads (A) gegen die Ressourcennutzung durch nicht genügend Threads für die Arbeit (B) abwägen.
(A) ist im Allgemeinen die Speichernutzung (Stapel usw.), da ein Thread, der keine Arbeit erledigt, nicht viel von der CPU verbraucht. (B) ist im Allgemeinen eine Verzögerung bei der Verarbeitung von Anfragen, sobald diese eintreffen, da Sie warten müssen, bis ein Thread verfügbar ist.
Deshalb messen Sie. Wie Sie angeben, wartet die überwiegende Mehrheit Ihrer Threads auf eine Antwort aus der Datenbank, damit sie nicht ausgeführt werden. Es gibt zwei Faktoren, die sich darauf auswirken, wie viele Threads Sie zulassen sollten.
Die erste ist die Anzahl der verfügbaren DB-Verbindungen. Dies kann eine harte Grenze sein, es sei denn, Sie können sie am DBMS erhöhen. Ich gehe davon aus, dass Ihr DBMS in diesem Fall eine unbegrenzte Anzahl von Verbindungen aufnehmen kann (obwohl Sie dies idealerweise auch messen sollten).
Dann hängt die Anzahl der Threads, die Sie haben sollten, von Ihrer historischen Verwendung ab. Das Minimum, das Sie ausführen sollten, ist die Mindestanzahl, die Sie jemals ausgeführt haben, + A%, mit einem absoluten Minimum von (zum Beispiel und konfigurierbar wie A) 5.
Die maximale Anzahl von Threads sollte Ihr historisches Maximum + B% sein.
Sie sollten auch auf Verhaltensänderungen überwachen. Wenn Ihre Nutzung aus irgendeinem Grund für einen längeren Zeitraum zu 100% verfügbar ist (so dass dies die Leistung der Clients beeinträchtigt), sollten Sie das zulässige Maximum erhöhen, bis es wieder um B% höher ist.
Als Antwort auf die Frage "Was genau soll ich messen?" Frage:
Was Sie speziell messen sollten, ist die maximale Anzahl von Threads, die gleichzeitig geladen werden (z. B. auf eine Rückkehr vom DB-Aufruf warten). Dann fügen Sie einen Sicherheitsfaktor von 10% für Beispiel (hervorgehoben, da andere Plakate scheinen meine Beispiele als feste Empfehlungen zu nehmen).
Darüber hinaus sollte dies in der Produktionsumgebung zum Optimieren erfolgen. Es ist in Ordnung, vorher einen Kostenvoranschlag zu erhalten, aber Sie wissen nie, welche Produktion Ihren Weg finden wird (weshalb all diese Dinge zur Laufzeit konfigurierbar sein sollten). Dies dient dazu, eine Situation wie eine unerwartete Verdoppelung der eingehenden Clientanrufe zu erfassen.
quelle
Diese Frage wurde ziemlich gründlich besprochen und ich hatte nicht die Gelegenheit, alle Antworten zu lesen. Bei der Betrachtung der Obergrenze für die Anzahl gleichzeitiger Threads, die in einem bestimmten System friedlich nebeneinander existieren können, sind jedoch einige Dinge zu beachten.
Jetzt können Sie Ihre Stapelgröße anpassen, um mehr Threads aufzunehmen, aber dann müssen Sie den Aufwand für die Thread-Verwaltung (Erstellung / Zerstörung und Planung) berücksichtigen. Sie können die CPU-Affinität zu einem bestimmten Prozess sowie zu einem bestimmten Thread erzwingen, um sie an bestimmte CPUs zu binden, um den Aufwand für die Thread-Migration zwischen den CPUs zu vermeiden und Probleme mit dem Kaltgeld zu vermeiden.
Beachten Sie, dass man auf Wunsch Tausende von Threads erstellen kann, aber wenn Linux keine VM mehr hat, werden nur zufällig Prozesse (also Threads) beendet. Dies soll verhindern, dass das Dienstprogrammprofil maximal genutzt wird. (Die Utility-Funktion informiert über das systemweite Utility für eine bestimmte Anzahl von Ressourcen. Bei konstanten Ressourcen in diesem Fall CPU-Zyklen und Speicher wird die Utility-Kurve mit immer mehr Aufgaben flacher.)
Ich bin sicher, dass der Windows-Kernel-Scheduler auch etwas in dieser Art unternimmt, um die Überauslastung der Ressourcen zu beheben
[1] http://adywicaksono.wordpress.com/2007/07/10/i-can-not-create-more-than-255-threads-on-linux-what-is-the-solutions/
quelle
Wenn Ihre Threads ressourcenintensive Arbeiten ausführen (CPU / Festplatte), werden Sie selten Vorteile sehen, die über ein oder zwei hinausgehen, und zu viele beeinträchtigen die Leistung sehr schnell.
Der "beste Fall" ist, dass Ihre späteren Threads blockieren, während die ersten abgeschlossen sind, oder dass einige Blöcke mit geringem Overhead für Ressourcen mit geringen Konflikten haben. Im schlimmsten Fall fangen Sie an, den Cache / die Festplatte / das Netzwerk zu zerstören, und Ihr Gesamtdurchsatz sinkt durch den Boden.
Eine gute Lösung besteht darin, Anforderungen in einem Pool zu platzieren, die dann aus einem Thread-Pool an Worker-Threads gesendet werden (und ja, die Vermeidung der kontinuierlichen Erstellung / Zerstörung von Threads ist ein guter erster Schritt).
Die Anzahl der aktiven Threads in diesem Pool kann dann basierend auf den Ergebnissen Ihrer Profilerstellung, der Hardware, auf der Sie ausgeführt werden, und anderen Dingen, die möglicherweise auf dem Computer auftreten, angepasst und skaliert werden.
quelle
Eine Sache, die Sie beachten sollten, ist, dass Python (zumindest die C-basierte Version) eine sogenannte globale Interpretersperre verwendet , die einen großen Einfluss auf die Leistung auf Multicore-Computern haben kann.
Wenn Sie wirklich das Beste aus Multithread-Python herausholen möchten, sollten Sie Jython oder ähnliches verwenden.
quelle
Wie Pax zu Recht sagte, messen Sie, raten Sie nicht . Das, was ich für DNSwitness und die Ergebnisse getan habe, war überraschend: Die ideale Anzahl von Threads war viel höher als ich dachte, ungefähr 15.000 Threads, um die schnellsten Ergebnisse zu erzielen.
Natürlich hängt es von vielen Dingen ab, deshalb müssen Sie sich selbst messen.
Vollständige Maßnahmen (nur auf Französisch) in Combien de fils d'exécution? .
quelle
Ich habe eine Reihe von Multithread-Apps geschrieben. Im Allgemeinen erlaube ich, dass die Anzahl potenzieller Threads durch eine Konfigurationsdatei angegeben wird. Wenn ich mich auf bestimmte Kunden eingestellt habe, habe ich die Anzahl so hoch eingestellt, dass meine Auslastung aller CPU-Kerne ziemlich hoch war, aber nicht so hoch, dass ich auf Speicherprobleme stieß (dies waren 32-Bit-Betriebssysteme bei der Zeit).
Anders ausgedrückt: Sobald Sie einen Engpass erreicht haben, sei es CPU, Datenbankdurchsatz, Festplattendurchsatz usw., wird das Hinzufügen weiterer Threads die Gesamtleistung nicht erhöhen. Aber bis Sie diesen Punkt erreicht haben, fügen Sie weitere Threads hinzu!
Beachten Sie, dass dies voraussetzt, dass die betreffenden Systeme für Ihre App reserviert sind und Sie andere Apps nicht gut spielen müssen (vermeiden, zu verhungern).
quelle
Die Antwort "Big Iron" lautet im Allgemeinen ein Thread pro begrenzter Ressource - Prozessor (CPU-gebunden), Arm (E / A-gebunden) usw. -, aber das funktioniert nur, wenn Sie die Arbeit an den richtigen Thread für die Ressource weiterleiten können zugegriffen werden.
Wenn dies nicht möglich ist, denken Sie daran, dass Sie über fungible Ressourcen (CPUs) und nicht fungible Ressourcen (Arme) verfügen. Für CPUs ist es nicht kritisch, jeden Thread einer bestimmten CPU zuzuweisen (obwohl dies bei der Cache-Verwaltung hilfreich ist), aber für Arme, wenn Sie dem Arm keinen Thread zuweisen können, beginnen Sie mit der Warteschlangentheorie und der optimalen Anzahl, um Arme zu behalten beschäftigt. Im Allgemeinen denke ich, dass wenn Sie Anfragen basierend auf dem verwendeten Arm nicht weiterleiten können, 2-3 Threads pro Arm ungefähr richtig sind.
Eine Komplikation entsteht, wenn die an den Thread übergebene Arbeitseinheit keine einigermaßen atomare Arbeitseinheit ausführt. Beispielsweise kann der Thread an einem Punkt auf die Festplatte zugreifen und an einem anderen Punkt in einem Netzwerk warten. Dies erhöht die Anzahl der "Risse", in die zusätzliche Threads eindringen und nützliche Arbeit leisten können, erhöht jedoch auch die Möglichkeit, dass zusätzliche Threads die Caches usw. des anderen verschmutzen und das System blockieren.
Natürlich müssen Sie dies alles gegen das "Gewicht" eines Fadens abwägen. Leider haben die meisten Systeme sehr schwere Threads (und was sie "leichte Threads" nennen, sind oft überhaupt keine Threads), daher ist es besser, auf der niedrigen Seite zu irren.
Was ich in der Praxis gesehen habe, ist, dass sehr subtile Unterschiede einen enormen Unterschied darin machen können, wie viele Threads optimal sind. Insbesondere Cache-Probleme und Sperrkonflikte können die praktische Parallelität erheblich einschränken.
quelle
Zu berücksichtigen ist, wie viele Kerne auf dem Computer vorhanden sind, auf dem der Code ausgeführt wird. Dies stellt eine feste Grenze für die Anzahl der Threads dar, die gleichzeitig ausgeführt werden können. Wenn jedoch wie in Ihrem Fall erwartet wird, dass Threads häufig darauf warten, dass eine Datenbank eine Abfrage ausführt, sollten Sie Ihre Threads wahrscheinlich basierend auf der Anzahl der gleichzeitigen Abfragen optimieren, die die Datenbank verarbeiten kann.
quelle
Ich denke, das ist ein bisschen ein Ausweichen vor Ihrer Frage, aber warum nicht sie in Prozesse einteilen? Mein Verständnis von Netzwerken (aus den trüben Tagen von früher, ich codiere Netzwerke überhaupt nicht) war, dass jede eingehende Verbindung als separater Prozess behandelt werden kann, denn wenn dann jemand etwas Böses in Ihrem Prozess tut, tut es dies nicht nuke das gesamte Programm.
quelle
Ryeguy, ich entwickle gerade eine ähnliche Anwendung und meine Thread-Nummer ist auf 15 gesetzt. Leider stürzt sie ab, wenn ich sie auf 20 erhöhe. Ja, ich denke, der beste Weg, dies zu handhaben, besteht darin, zu messen, ob Ihre aktuelle Konfiguration mehr oder weniger als eine Anzahl X von Threads zulässt.
quelle
In den meisten Fällen sollten Sie dem Thread-Pool erlauben, dies zu handhaben. Wenn Sie Code veröffentlichen oder weitere Details angeben, ist es möglicherweise einfacher festzustellen, ob das Standardverhalten des Thread-Pools aus irgendeinem Grund nicht am besten ist.
Weitere Informationen dazu finden Sie hier: http://en.wikipedia.org/wiki/Thread_pool_pattern
quelle
So viele Threads wie die CPU-Kerne habe ich sehr oft gehört.
quelle