it-swarm.com.de

Threads vs Prozesse in Linux

Ich habe kürzlich von einigen Leuten gehört, dass es unter Linux fast immer besser ist, Prozesse anstelle von Threads zu verwenden, da Linux Prozesse sehr effizient verarbeitet und mit Threads so viele Probleme (wie das Sperren) verbunden sind. Ich bin jedoch misstrauisch, weil es den Anschein hat, als könnten Threads in einigen Situationen einen ziemlich großen Leistungsgewinn bringen.

Meine Frage ist also, ob ich in einer Situation, in der sowohl Threads als auch Prozesse ziemlich gut funktionieren können, Prozesse oder Threads verwenden soll. Wenn ich zum Beispiel einen Webserver schreibe, sollte ich Prozesse oder Threads (oder eine Kombination) verwenden?

237
user17918

Linux verwendet ein 1-1-Threading-Modell, bei dem (für den Kernel) keine Unterscheidung zwischen Prozessen und Threads besteht - alles ist einfach eine ausführbare Aufgabe. *

Unter Linux klont der Systemaufruf clone eine Aufgabe mit einer konfigurierbaren Freigabeebene, darunter:

  • CLONE_FILES: Teile die gleiche Dateideskriptortabelle (anstatt eine Kopie zu erstellen)
  • CLONE_PARENT: Stellt keine Eltern-Kind-Beziehung zwischen der neuen und der alten Aufgabe her (ansonsten getppid() = Eltern getpid())
  • CLONE_VM: Teile den gleichen Speicherplatz (anstatt eine KUH Kopie zu erstellen)

fork() ruft clone( auf, das am wenigsten ) teilt, und pthread_create() ruft clone( auf, das am meisten ) teilt. **

forking kostet ein kleines bisschen mehr als pthread_create, weil Tabellen kopiert und COW-Zuordnungen für den Speicher erstellt wurden, aber die Linux-Kernel-Entwickler haben versucht (und es geschafft), diese Kosten zu minimieren.

Das Wechseln zwischen Tasks, wenn sie denselben Speicherplatz und verschiedene Tabellen gemeinsam nutzen, ist ein wenig billiger als das Wechseln, wenn sie nicht gemeinsam genutzt werden, da die Daten möglicherweise bereits im Cache geladen sind. Das Wechseln von Aufgaben ist jedoch immer noch sehr schnell, selbst wenn nichts geteilt wird - dies ist etwas anderes, das Linux-Kernel-Entwickler sicherstellen möchten (und das auch sicherstellen können).

Wenn Sie sich auf einem Multiprozessorsystem befinden, kann keine Freigabe für die Leistung von Vorteil sein: Wenn jede Aufgabe auf einem anderen Prozessor ausgeführt wird, Das Synchronisieren von gemeinsam genutztem Speicher ist teuer.


* Vereinfacht CLONE_THREAD Bewirkt, dass die Signalübermittlung gemeinsam genutzt wird (was CLONE_SIGHAND Benötigt, das die Signalhandlertabelle gemeinsam nutzt).

** Vereinfacht. Es gibt beide Systemaufrufe SYS_fork Und SYS_clone, Aber im Kernel sind sys_fork Und sys_clone Sehr dünne Wrapper um dasselbe do_fork. ] Funktion, die selbst eine dünne Hülle um copy_process ist. Ja, die Begriffe process, thread und task werden im Linux-Kernel eher synonym verwendet ...

307
ephemient

Linux (und in der Tat Unix) gibt 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. Das Programm führt Kopien von sich aus, um Aufgaben an zu delegieren.

Option 2 - Threads

Erstellen Sie eine eigenständige ausführbare Datei, die mit einem einzelnen Thread gestartet wird, 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 in Wirklichkeit ein eigener Prozess mit einem eigenen Adressraum. Das Kind kann (normalerweise) nichts tun, um den Adressraum seiner Eltern oder Geschwister zu beeinflussen (im Gegensatz zu einem Thread). Sie erhalten also zusätzliche Robustheit.

Die Speicherseiten werden jedoch nicht kopiert, sie werden beim Schreiben kopiert, sodass normalerweise weniger Speicher verwendet wird, als Sie sich vorstellen können.

Stellen Sie sich ein Webserver-Programm vor, das aus zwei Schritten besteht:

  1. Konfigurations- und Laufzeitdaten lesen
  2. Seitenanfragen bedienen

Wenn Sie Threads verwendet haben, wird Schritt 1 einmal und Schritt 2 in mehreren Threads ausgeführt. Wenn Sie "herkömmliche" Prozesse verwenden, müssen die Schritte 1 und 2 für jeden Prozess wiederholt werden, und der Speicher zum Speichern der Konfigurations- und Laufzeitdaten muss dupliziert werden. Wenn Sie fork () verwendet haben, können Sie Schritt 1 und dann fork () ausführen, wobei die Laufzeitdaten und die Konfiguration im Speicher bleiben und nicht kopiert werden.

Es gibt also drei Möglichkeiten.

57
MarkR

Das hängt von vielen Faktoren ab. Prozesse sind schwerer als Threads und verursachen höhere Kosten für das Starten und Herunterfahren. Interprocess Communication (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 einen Pufferüberlauf aufweist, hat dies keine Auswirkungen auf einen anderen Prozess. Wenn ein Thread abstürzt, werden alle anderen Threads im Prozess heruntergefahren, und wenn ein Thread einen Pufferüberlauf aufweist, wird er geöffnet ein Sicherheitsloch in allen Threads.

Wenn die Module Ihrer Anwendung weitgehend 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 Performance - Hit von IPC ist minimal, und Sie sind etwas sicherer gegenüber Bugs und Sicherheitslücken. Wenn Sie jede Leistung benötigen, können Sie eine Menge gemeinsam genutzter Daten (z als komplexe Datenstrukturen) mit Threads gehen.

50
Adam Rosenfield

Andere haben die Überlegungen diskutiert.

Vielleicht liegt der wichtige Unterschied darin, dass Windows-Prozesse im Vergleich zu Threads schwer und teuer sind, und dass der Unterschied unter Linux viel geringer ist, sodass die Gleichung an einem anderen Punkt ausgeglichen wird.

10
dmckee

Es war einmal Unix und in diesem guten alten Unix gab es viel Overhead für Prozesse. Einige clevere Leute erstellten Threads, die denselben Adressraum wie der übergeordnete Prozess hatten und nur einen reduzierten Kontext benötigten switch, wodurch der Kontextwechsel effizienter wird.

In einem zeitgenössischen Linux (2.6.x) gibt es keinen großen Unterschied in der Leistung zwischen einem Kontextwechsel eines Prozesses und einem Thread (nur das MMU Zeug ist zusätzlich für den Thread) das Problem mit dem gemeinsam genutzten Adressraum, was bedeutet, dass ein fehlerhafter Zeiger in einem Thread den Speicher des übergeordneten Prozesses oder eines anderen Threads innerhalb desselben Adressraums 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 bräuchte, die alles in allem eine andere Sache ist.

Warum glauben Sie, haben Threads unter Linux einen so großen Leistungszuwachs? Haben Sie Daten dafür oder ist es nur ein Mythos?

8
robert.berger

Wie eng sind Ihre Aufgaben miteinander verbunden?

Wenn sie unabhängig voneinander leben können, dann nutzen Sie Prozesse. Wenn sie aufeinander angewiesen sind, verwenden Sie Threads. Auf diese Weise können Sie einen fehlerhaften Prozess beenden und neu starten, ohne den Betrieb der anderen Tasks zu beeinträchtigen.

5
Robert

Um die Sache noch weiter zu komplizieren, gibt es so etwas wie thread-local storage und Unix Shared Memory.

Thread-lokaler Speicher ermöglicht es jedem Thread, eine separate Instanz globaler Objekte zu haben. Ich habe es nur beim Erstellen einer Emulationsumgebung unter Linux/Windows für Anwendungscode verwendet, der unter einem RTOS ausgeführt wurde. In RTOS) war jede Aufgabe ein Prozess mit einem eigenen Adressraum, in der Emulationsumgebung war jede Aufgabe ein Thread (mit einem gemeinsamen Adressraum). Durch die Verwendung von TLS für Dinge wie Singletons haben wir konnten eine separate Instanz für jeden Thread haben, genau wie in der 'echten' RTOS Umgebung.

Shared Memory bietet (offensichtlich) den Leistungsvorteil, dass mehrere Prozesse auf denselben Speicher zugreifen, jedoch auf Kosten/Risiko, dass die Prozesse ordnungsgemäß synchronisiert werden müssen. Eine Möglichkeit hierfür besteht darin, dass ein Prozess eine Datenstruktur im gemeinsam genutzten Speicher erstellt und dann ein Handle über die herkömmliche Kommunikation zwischen Prozessen (wie eine Named Pipe) an diese Struktur sendet.

4
KeyserSoze

Die Entscheidung zwischen Thread/Prozess hängt ein wenig davon ab, wofür Sie ihn verwenden werden. Einer der Vorteile eines Prozesses ist, dass er eine PID hat und getötet werden kann, ohne dass auch der übergeordnete Prozess 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. Kommentarescheintz stimmen zu, dass Prozesse robuster sind, Threads jedoch eine etwas bessere Leistung erbringen können (mit Ausnahme von Fenstern, in denen die Leistung für Prozesse schlecht ist und Sie nur Threads verwenden wollen).

3
hlovdal

Ich muss dem zustimmen, was Sie gehört haben. Beim Benchmarking unseres Clusters (xhpl und dergleichen) erzielen wir bei Prozessen über Threads immer eine deutlich bessere Leistung. </anecdote>

3
eduffy

In meiner jüngsten Arbeit mit Linux ist eine Sache zu beachten, Bibliotheken. Wenn Sie Threads verwenden, stellen Sie sicher, dass alle Bibliotheken, die Sie für mehrere Threads 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 bekommen.

3
aal8

In den meisten Fällen würde ich Prozesse gegenüber Threads bevorzugen. Threads können nützlich sein, wenn Sie eine relativ kleine Aufgabe haben (Verarbeitungsaufwand >> Zeit, die von jeder unterteilten Aufgabeneinheit benötigt wird) und eine gemeinsame Speichernutzung zwischen ihnen erforderlich ist. Denken Sie an ein großes Feld. Beachten Sie auch (offtopic), dass Multithreading oder die Verarbeitung keinen Vorteil bringen, wenn Ihre CPU-Auslastung zu 100 Prozent oder in der Nähe davon liegt. (in der Tat wird es sich verschlechtern)

2
neal aise

Ich denke, alle haben großartige Arbeit geleistet, um auf Ihre Frage zu antworten. Ich füge nur weitere Informationen zu Thread und Prozess in Linux hinzu, um einige der vorherigen Antworten im Kontext des Kernels zu verdeutlichen und zusammenzufassen. Meine Antwort bezieht sich also auf kernelspezifischen Code in Linux. Laut Linux-Kernel-Dokumentation gibt es keine klare Unterscheidung zwischen Thread und Prozess, außer dass der Thread im Gegensatz zum Prozess gemeinsam genutzten virtuellen Adressraum verwendet. Beachten Sie auch, dass der Linux-Kernel den Begriff "Task" für "Prozess" und "Thread" im Allgemeinen verwendet.

"Es gibt keine internen Strukturen, die Prozesse oder Threads implementieren, sondern eine Struktur task_struct, die eine abstrakte Planungseinheit namens task beschreibt"

Laut Linus Torvalds sollten Sie auch NICHT über Prozesse oder Threads nachdenken, da dies zu einschränkend ist und der einzige Unterschied in Bezug auf die Trennung des Adressraums vom übergeordneten oder gemeinsam genutzten Adressraum im COE oder im Kontext der Ausführung besteht. Tatsächlich verwendet er ein Webserver-Beispiel, um seinen Standpunkt zu verdeutlichen hier (was das Lesen sehr empfehlenswert macht).

Voller Dank an Linux-Kernel-Dokumentation

1
grepit

Threads -> Threads teilen sich einen Speicherplatz, es ist eine Abstraktion der CPU, es ist leichtgewichtig. Prozesse -> Prozesse haben einen eigenen Speicherplatz, es ist eine Abstraktion eines Computers. Um eine 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 ein Prozess verwendet und eine geringere Latenzzeit bietet. Ein Beispiel für das Web wäre chrome und firefox. Im Falle von Chrome= ist jeder Tab ein neuer Prozess, daher ist die Speichernutzung chrome ist höher als Firefox, während die Sicherheit und Stabilität besser ist als bei Firefox. Die Sicherheit, die hier durch chrome bereitgestellt wird, ist besser, da jeder Tab ein neuer Prozess ist, in den ein anderer Tab nicht hineinschnüffeln kann der Speicherplatz eines bestimmten Prozesses.