Ich habe kürzlich einige Leute sagen hören, dass es unter Linux fast immer besser ist, Prozesse anstelle von Threads zu verwenden, da Linux Prozesse sehr effizient handhabt und mit Threads so viele Probleme (wie das Sperren) verbunden sind. Ich bin jedoch misstrauisch, da Threads in einigen Situationen einen ziemlich großen Leistungsgewinn bringen könnten.
Meine Frage ist also, ob ich in einer Situation, in der Threads und Prozesse ziemlich gut umgehen können, Prozesse oder Threads verwenden sollte. Wenn ich beispielsweise einen Webserver schreibe, sollte ich Prozesse oder Threads (oder eine Kombination) verwenden?
linux
performance
multithreading
process
user17918
quelle
quelle
Antworten:
Linux verwendet ein 1-1-Threading-Modell, bei dem (für den Kernel) nicht zwischen Prozessen und Threads unterschieden wird - alles ist einfach eine ausführbare Aufgabe. * *
Unter Linux klont der Systemaufruf
clone
eine Aufgabe mit einer konfigurierbaren Freigabeebene, darunter:CLONE_FILES
: Verwenden Sie dieselbe Dateideskriptortabelle (anstatt eine Kopie zu erstellen).CLONE_PARENT
: Richten Sie keine Eltern-Kind-Beziehung zwischen der neuen und der alten Aufgabe ein (andernfalls Kindgetppid()
= Elterngetpid()
)CLONE_VM
: denselben Speicherplatz gemeinsam nutzen (anstatt eine COW- Kopie zu erstellen )fork()
ruft amclone(
wenigsten teilen)
undpthread_create()
ruftclone(
am meisten teilen auf)
. ** **.fork
Daspthread_create
Kopieren von Tabellen und das Erstellen von COW-Zuordnungen für den Speicher kostet ein kleines bisschen mehr als das Kopieren von Tabellen, aber die Linux-Kernel-Entwickler haben versucht (und es geschafft), diese Kosten zu minimieren.Das Wechseln zwischen Aufgaben, wenn sie denselben Speicherplatz und verschiedene Tabellen gemeinsam nutzen, ist ein kleines bisschen billiger als wenn sie nicht gemeinsam genutzt werden, da die Daten möglicherweise bereits in den Cache geladen sind. Das Wechseln von Aufgaben ist jedoch immer noch sehr schnell, auch wenn nichts gemeinsam genutzt wird. Dies ist etwas anderes, das Linux-Kernel-Entwickler sicherstellen möchten (und das sie erfolgreich sicherstellen können).
In der Tat, wenn Sie auf einem Multi-Prozessor - System sind, nicht kann Sharing Leistung tatsächlich von Vorteil: wenn jede Aufgabe auf einem anderen Prozessor ausgeführt wird , gemeinsam genutzten Speicher teuer ist synchronisiert.
* Vereinfacht.
CLONE_THREAD
bewirktCLONE_SIGHAND
, dass die Signalübertragung gemeinsam genutzt wird (was benötigt wird , wodurch die Signalhandlertabelle gemeinsam genutzt wird).** Vereinfacht. Es gibt sowohl
SYS_fork
als auchSYS_clone
syscalls, aber im Kernel sind diesys_fork
undsys_clone
beide sehr dünne Wrapper um dieselbedo_fork
Funktion, die selbst ein dünner Wrapper istcopy_process
. Ja, die Begriffeprocess
,thread
undtask
sind eher austauschbar in dem Linux - Kernel verwendet ...quelle
socket
,bind
,listen
,fork
, und haben dann mehrere Prozesseaccept
Verbindungen auf demselben Socket. Ein Prozess kann die Annahme beenden, wenn er ausgelastet ist, und der Kernel leitet eingehende Verbindungen an einen anderen Prozess weiter (wenn niemand zuhört, wird der Kernel je nachlisten
Rückstand in die Warteschlange gestellt oder gelöscht). Sie haben nicht viel mehr Kontrolle über die Arbeitsverteilung als das, aber normalerweise ist das gut genug!clone()
um zu bestimmen, welche Ressourcen gemeinsam genutzt werden. Eine Aufgabe kann auchunshare()
zu einem späteren Zeitpunkt Ressourcen bereitstellen.task_struct
für jede Aufgabe eine. Dies wird im gesamten Kernel-Code häufig als "Prozess" bezeichnet, entspricht jedoch jedem ausführbaren Thread. Es gibt keineprocess_struct
; Wenn eine Reihe vontask_struct
s durch ihrethread_group
Liste miteinander verbunden sind , sind sie der gleiche "Prozess" für den Benutzerbereich. Es gibt ein wenig spezielle Behandlung von "Threads", z. B. werden alle Geschwister-Threads auf Fork und Exec gestoppt und nur der "Haupt" -Thread wird in angezeigtls /proc
. Auf jeden Thread kann jedoch zugegriffen werden/proc/pid
, unabhängig davon, ob er in aufgeführt ist/proc
oder nicht.clone(CLONE_THREAD | CLONE_VM | CLONE_SIGHAND))
würden Sie einen neuen "Thread" erhalten, der kein Arbeitsverzeichnis, keine Dateien oder Sperren gemeinsam nutzt, währendclone(CLONE_FILES | CLONE_FS | CLONE_IO)
Sie einen "Prozess" erhalten, der dies tut. Das zugrunde liegende System erstellt Aufgaben durch Klonen.fork()
undpthread_create()
sind nur Bibliotheksfunktionen, dieclone()
anders aufrufen (wie ich in dieser Antwort geschrieben habe).Linux (und in der Tat Unix) bietet Ihnen eine dritte Option.
Option 1 - Prozesse
Erstellen Sie eine eigenständige ausführbare Datei, die einen Teil (oder alle Teile) Ihrer Anwendung verarbeitet, und rufen Sie sie für jeden Prozess separat auf, z. B. führt das Programm Kopien von sich selbst aus, an die Aufgaben delegiert werden sollen.
Option 2 - Threads
Erstellen Sie eine eigenständige ausführbare Datei, die mit einem einzelnen Thread startet, und erstellen Sie zusätzliche Threads, um einige Aufgaben auszuführen
Option 3 - Gabel
Nur unter Linux / Unix verfügbar, das ist etwas anders. Ein gegabelter Prozess ist wirklich ein eigener Prozess mit einem eigenen Adressraum - es gibt nichts, was das Kind (normalerweise) tun kann, um den Adressraum seiner Eltern oder Geschwister zu beeinflussen (im Gegensatz zu einem Thread) -, sodass Sie zusätzliche Robustheit erhalten.
Die Speicherseiten werden jedoch nicht kopiert, sondern beim Schreiben kopiert, sodass normalerweise weniger Speicher verwendet wird, als Sie sich vorstellen können.
Stellen Sie sich ein Webserverprogramm vor, das aus zwei Schritten besteht:
Wenn Sie Threads verwendet haben, wird Schritt 1 einmal und Schritt 2 in mehreren Threads ausgeführt. Wenn Sie "traditionelle" Prozesse verwenden, müssen die Schritte 1 und 2 für jeden Prozess wiederholt und der Speicher zum Speichern der Konfigurations- und Laufzeitdaten dupliziert werden. Wenn Sie fork () verwendet haben, können Sie Schritt 1 einmal und dann fork () ausführen, wobei die Laufzeitdaten und die Konfiguration im Speicher unberührt bleiben und nicht kopiert werden.
Es gibt also wirklich drei Möglichkeiten.
quelle
Das hängt von vielen Faktoren ab. Prozesse sind schwerer als Threads und verursachen höhere Kosten für das Starten und Herunterfahren. Interprozesskommunikation (IPC) ist auch schwieriger und langsamer als Interthread-Kommunikation.
Umgekehrt sind Prozesse sicherer und sicherer als Threads, da jeder Prozess in einem eigenen virtuellen Adressraum ausgeführt wird. Wenn ein Prozess abstürzt oder ein Pufferüberlauf auftritt, wirkt sich dies überhaupt nicht auf einen anderen Prozess aus. Wenn ein Thread abstürzt, werden alle anderen Threads im Prozess heruntergefahren, und wenn ein Thread einen Pufferüberlauf aufweist, wird er geöffnet eine Sicherheitslücke in allen Fäden.
Wenn die Module Ihrer Anwendung größtenteils unabhängig und mit wenig Kommunikation ausgeführt werden können, sollten Sie wahrscheinlich Prozesse verwenden, wenn Sie sich die Kosten für das Starten und Herunterfahren leisten können. Der Leistungseinbruch von IPC ist minimal und Sie sind etwas sicherer gegen Fehler und Sicherheitslücken. Wenn Sie jede Leistung benötigen, die Sie erhalten können, oder viele gemeinsam genutzte Daten (z. B. komplexe Datenstrukturen) haben, verwenden Sie Threads.
quelle
Andere haben die Überlegungen diskutiert.
Möglicherweise besteht der wichtige Unterschied darin, dass in Windows-Prozessen im Vergleich zu Threads schwere und teure Prozesse ausgeführt werden und in Linux der Unterschied viel geringer ist, sodass die Gleichung an einem anderen Punkt ausgeglichen wird.
quelle
Es war einmal Unix und in diesem guten alten Unix gab es viel Aufwand für Prozesse. Einige clevere Leute haben also Threads erstellt, die denselben Adressraum mit dem übergeordneten Prozess teilen und nur einen reduzierten Kontext benötigen switch, wodurch der Kontextwechsel effizienter wird.
In einem modernen Linux (2.6.x) gibt es keinen großen Leistungsunterschied zwischen einem Kontextwechsel eines Prozesses und einem Thread (nur das MMU-Material ist für den Thread zusätzlich). Es gibt ein Problem mit dem gemeinsam genutzten Adressraum. Dies bedeutet, dass ein fehlerhafter Zeiger in einem Thread den Speicher des übergeordneten Prozesses oder eines anderen Threads im selben Adressraum beschädigen kann.
Ein Prozess ist durch die MMU geschützt, sodass ein fehlerhafter Zeiger nur ein Signal 11 und keine Beschädigung verursacht.
Ich würde im Allgemeinen Prozesse verwenden (nicht viel Overhead für Kontextwechsel unter Linux, aber Speicherschutz aufgrund von MMU), aber pthreads, wenn ich eine Echtzeit-Scheduler-Klasse benötigen würde, die insgesamt eine andere Tasse Tee ist.
Warum haben Threads unter Linux Ihrer Meinung nach einen so großen Leistungsgewinn? Haben Sie Daten dafür oder ist es nur ein Mythos?
quelle
Wie eng sind Ihre Aufgaben gekoppelt?
Wenn sie unabhängig voneinander leben können, verwenden Sie Prozesse. Wenn sie sich aufeinander verlassen, verwenden Sie Threads. Auf diese Weise können Sie einen fehlerhaften Prozess beenden und neu starten, ohne den Betrieb der anderen Aufgaben zu beeinträchtigen.
quelle
Um die Sache noch weiter zu verkomplizieren, gibt es einen threadlokalen Speicher und einen gemeinsam genutzten Unix-Speicher.
Durch den threadlokalen Speicher kann jeder Thread eine separate Instanz globaler Objekte haben. Das einzige Mal, dass ich es verwendet habe, war beim Erstellen einer Emulationsumgebung unter Linux / Windows für Anwendungscode, der in einem RTOS ausgeführt wurde. Im RTOS war jede Aufgabe ein Prozess mit einem eigenen Adressraum, in der Emulationsumgebung war jede Aufgabe ein Thread (mit einem gemeinsam genutzten Adressraum). Durch die Verwendung von TLS für Dinge wie Singletons konnten wir für jeden Thread eine eigene Instanz haben, genau wie in der "echten" RTOS-Umgebung.
Shared Memory kann Ihnen (offensichtlich) die Leistungsvorteile bieten, wenn mehrere Prozesse auf denselben Speicher zugreifen, jedoch auf Kosten / Risiko einer ordnungsgemäßen Synchronisierung der Prozesse. Eine Möglichkeit, dies zu tun, besteht darin, dass ein Prozess eine Datenstruktur im gemeinsam genutzten Speicher erstellt und dann über die herkömmliche Kommunikation zwischen Prozessen (wie eine Named Pipe) ein Handle an diese Struktur sendet.
quelle
In meiner jüngsten Arbeit mit LINUX ist eine Sache zu beachten, sind Bibliotheken. Wenn Sie Threads verwenden, stellen Sie sicher, dass alle Bibliotheken, die Sie über Threads hinweg verwenden können, threadsicher sind. Das hat mich ein paar Mal verbrannt. Insbesondere ist libxml2 nicht sofort threadsicher. Es kann mit thread safe kompiliert werden, aber das ist nicht das, was Sie mit aptitude install erhalten.
quelle
Ich muss dem zustimmen, was Sie gehört haben. Wenn wir unseren Cluster (
xhpl
und dergleichen) vergleichen, erzielen wir mit Prozessen über Threads immer eine deutlich bessere Leistung.</anecdote>
quelle
Die Entscheidung zwischen Thread / Prozess hängt ein wenig davon ab, wofür Sie ihn verwenden werden. Einer der Vorteile eines Prozesses besteht darin, dass er eine PID hat und getötet werden kann, ohne dass auch der Elternteil beendet wird.
Für ein reales Beispiel eines Webservers unterstützte Apache 1.3 nur mehrere Prozesse. In 2.0 wurde jedoch eine Abstraktion hinzugefügt, sodass Sie zwischen beiden wechseln können. Kommentare scheint zu bestätigen , dass Prozesse robuster sind aber Threads kann ein wenig bessere Leistung ( mit Ausnahme von Fenstern , in denen die Leistung für Prozesse saugt und Sie wollen nur Threads verwenden).
quelle
In den meisten Fällen würde ich Prozesse Threads vorziehen. Threads können nützlich sein, wenn Sie eine relativ kleinere Aufgabe haben (Prozessaufwand >> Zeit, die von jeder geteilten Aufgabeneinheit benötigt wird) und eine gemeinsame Nutzung des Speichers zwischen ihnen erforderlich ist. Denken Sie an eine große Auswahl. Beachten Sie auch (offtopic), dass Multithreading oder -verarbeitung keinen Nutzen bringen, wenn Ihre CPU-Auslastung 100 Prozent oder nahe daran liegt. (in der Tat wird es sich verschlechtern)
quelle
Threads -> Threads teilen sich einen Speicherplatz, es ist eine Abstraktion der CPU, es ist leichtgewichtig. Prozesse -> Prozesse haben ihren eigenen Speicherplatz, es ist eine Abstraktion eines Computers. Um die Aufgabe zu parallelisieren, müssen Sie eine CPU abstrahieren. Die Vorteile der Verwendung eines Prozesses gegenüber einem Thread sind jedoch Sicherheit und Stabilität, während ein Thread weniger Speicher als der Prozess benötigt und eine geringere Latenz bietet. Ein Beispiel in Bezug auf Web wäre Chrom und Firefox. Im Falle von Chrome ist jede Registerkarte ein neuer Prozess, daher ist die Speichernutzung von Chrome höher als bei Firefox, während die bereitgestellte Sicherheit und Stabilität besser ist als bei Firefox. Die hier von Chrome bereitgestellte Sicherheit ist besser, da jede Registerkarte ein neuer Prozess ist. Eine andere Registerkarte kann nicht in den Speicherbereich eines bestimmten Prozesses eindringen.
quelle
Ich denke, jeder hat großartige Arbeit geleistet, um auf Ihre Frage zu antworten. Ich füge nur weitere Informationen zu Thread versus Prozess unter Linux hinzu, um einige der vorherigen Antworten im Zusammenhang mit dem Kernel zu klären und zusammenzufassen. Meine Antwort bezieht sich also auf kernelspezifischen Code unter Linux. Laut der Linux-Kernel-Dokumentation gibt es keine klare Unterscheidung zwischen Thread und Prozess, außer dass der Thread im Gegensatz zum Prozess einen gemeinsam genutzten virtuellen Adressraum verwendet. Beachten Sie auch, dass der Linux-Kernel den Begriff "Aufgabe" verwendet, um sich allgemein auf Prozess und Thread zu beziehen.
"Es gibt keine internen Strukturen, die Prozesse oder Threads implementieren. Stattdessen gibt es eine struct task_struct, die eine abstrakte Planungseinheit namens task beschreibt."
Laut Linus Torvalds sollten Sie auch NICHT an Prozess oder Thread denken, da dies zu einschränkend ist und der einzige Unterschied darin besteht, COE oder Ausführungskontext in Bezug auf "Trennen des Adressraums vom übergeordneten" oder gemeinsam genutzten Adressraum. In der Tat benutzt er ein Web - Server Beispiel zu seinem Punkt zu machen hier (die Lektüre sehr empfehlen).
Volle Gutschrift für die Linux-Kernel-Dokumentation
quelle
Wenn Sie Ressourcen gemeinsam nutzen müssen, sollten Sie wirklich Threads verwenden.
Berücksichtigen Sie auch die Tatsache, dass Kontextwechsel zwischen Threads viel billiger sind als Kontextwechsel zwischen Prozessen.
Ich sehe keinen Grund, explizit getrennte Prozesse durchzuführen, es sei denn, Sie haben einen guten Grund dafür (Sicherheit, bewährte Leistungstests usw.)
quelle