Warum ist das Erstellen eines neuen Prozesses unter Windows teurer als unter Linux?


100

Ich habe gehört, dass das Erstellen eines neuen Prozesses auf einer Windows-Box teurer ist als unter Linux. Ist das wahr? Kann jemand die technischen Gründe erklären, warum es teurer ist, und historische Gründe für die Entwurfsentscheidungen angeben, die hinter diesen Gründen stehen?

Antworten:


68

mweerden: NT wurde vom ersten Tag an für Mehrbenutzer entwickelt, daher ist dies kein wirklicher Grund. Sie haben jedoch Recht, dass die Prozesserstellung unter NT eine weniger wichtige Rolle spielt als unter Unix, da NT im Gegensatz zu Unix Multithreading gegenüber Multiprocessing bevorzugt.

Rob, es ist wahr, dass Gabel relativ billig ist, wenn COW verwendet wird, aber tatsächlich wird Gabel meistens von einem Exec gefolgt. Und ein Exec muss auch alle Bilder laden. Die Leistung der Gabel zu diskutieren ist daher nur ein Teil der Wahrheit.

Bei der Erörterung der Geschwindigkeit der Prozesserstellung ist es wahrscheinlich eine gute Idee, zwischen NT und Windows / Win32 zu unterscheiden. Was NT (dh den Kernel selbst) betrifft, denke ich nicht, dass die Prozesserstellung (NtCreateProcess) und die Thread-Erstellung (NtCreateThread) erheblich langsamer sind als bei durchschnittlichem Unix. Es ist vielleicht ein bisschen mehr los, aber ich sehe hier nicht den Hauptgrund für den Leistungsunterschied.

Wenn Sie sich jedoch Win32 ansehen, werden Sie feststellen, dass die Prozesserstellung dadurch einen erheblichen Aufwand verursacht. Zum einen muss das CSRSS über die Prozesserstellung informiert werden, an der LPC beteiligt ist. Es muss mindestens kernel32 zusätzlich geladen werden, und es muss eine Reihe zusätzlicher Buchhaltungsaufgaben ausführen, bevor der Prozess als vollwertiger Win32-Prozess betrachtet wird. Und vergessen wir nicht den zusätzlichen Aufwand, der durch das Parsen von Manifesten entsteht. Überprüfen Sie, ob für das Image ein Kompatibilitäts-Shim erforderlich ist, und prüfen Sie, ob Richtlinien für Softwareeinschränkungen gelten.

Das heißt, ich sehe die allgemeine Verlangsamung in der Summe all dieser kleinen Dinge, die zusätzlich zur rohen Erstellung eines Prozesses, des VA-Raums und des anfänglichen Threads getan werden müssen. Aber wie eingangs gesagt - aufgrund der Bevorzugung von Multithreading gegenüber Multitasking ist die einzige Software, die von diesen zusätzlichen Kosten ernsthaft betroffen ist, schlecht portierte Unix-Software. Obwohl sich diese Situation ändert, wenn Software wie Chrome und IE8 plötzlich die Vorteile der Mehrfachverarbeitung wieder entdecken und häufig Prozesse starten und abbauen ...


8
Auf Fork folgt nicht immer exec (), und die Leute kümmern sich nur um fork (). Apache 1.3 verwendet fork () (ohne exec) unter Linux und Threads unter Windows, auch wenn in vielen Fällen Prozesse gegabelt werden, bevor sie benötigt und in einem Pool gespeichert werden.
Blaisorblade

5
Nicht zu vergessen natürlich der Befehl 'vfork', der für das von Ihnen beschriebene Szenario 'just call exec' entwickelt wurde.
Chris Huang-Leaver

4
Eine andere Art von Software, die davon ernsthaft betroffen ist, ist jede Art von Shell-Scripting, bei dem mehrere Prozesse koordiniert werden. Bash-Scripting in Cygwin zum Beispiel leidet stark darunter. Stellen Sie sich eine Shell-Schleife vor, die viel Sed, Awk und Grep in Pipelines erzeugt. Jeder Befehl erzeugt einen Prozess und jede Pipe erzeugt eine Unterschale und einen neuen Prozess in dieser Unterschale. Unix wurde für diese Art der Verwendung entwickelt, weshalb eine schnelle Prozesserstellung dort die Norm bleibt.
Dan Moulding

5
-1. Die Behauptung, dass Software "schlecht portiert" ist, weil sie auf einem schlecht gestalteten Betriebssystem mit Kompatibilitätsproblemen, die die Prozesserstellung verlangsamen, nicht gut läuft, ist lächerlich.
Miles Rout

6
@MilesRout Das Ziel der Portierung besteht darin, die Software so zu ändern, dass sie auf einem neuen Zielsystem ausgeführt werden kann, wobei die Stärken und Mängel dieses Systems berücksichtigt werden. Portierte Software mit schlechter Leistung ist Software mit schlechter Portierung, unabhängig von den Hindernissen, die das Betriebssystem bietet.
Dizzyspiral

28

Unix hat einen 'Fork'-Systemaufruf, der den aktuellen Prozess in zwei Teile' aufteilt 'und Ihnen einen zweiten Prozess gibt, der mit dem ersten identisch ist (Modulo der Rückkehr vom Fork-Aufruf). Da der Adressraum des neuen Prozesses bereits aktiv ist, sollte dies billiger sein, als "CreateProcess" in Windows aufzurufen und das exe-Image, die zugehörigen DLLs usw. laden zu lassen.

In diesem Fall kann das Betriebssystem die "Copy-on-Write" -Semantik für die Speicherseiten verwenden, die beiden neuen Prozessen zugeordnet sind, um sicherzustellen, dass jede Seite eine eigene Kopie der Seiten erhält, die sie anschließend ändern.


21
Dieses Argument gilt nur, wenn Sie wirklich gabeln. Wenn Sie einen neuen Prozess starten, müssen Sie unter Unix immer noch forken und ausführen. Sowohl Windows als auch Unix haben beim Schreiben eine Kopie. Windows wird eine geladene EXE-Datei sicherlich wiederverwenden, wenn Sie eine zweite Kopie einer App ausführen. Ich denke nicht, dass Ihre Erklärung richtig ist, sorry.
Joel Spolsky


Ich habe meiner Antwort einige Leistungsdaten hinzugefügt. stackoverflow.com/a/51396188/537980 Sie können sehen, dass es schneller ist.
Strg-Alt-Delor

25

Hinzu kommt, was JP gesagt hat: Der größte Teil des Overheads gehört zum Win32-Start für den Prozess.

Der Windows NT-Kernel unterstützt tatsächlich COW Fork. SFU (Microsoft UNIX-Umgebung für Windows) verwendet sie. Win32 unterstützt Fork jedoch nicht. SFU-Prozesse sind keine Win32-Prozesse. SFU ist orthogonal zu Win32: Beide sind Umgebungssubsysteme, die auf demselben Kernel basieren.

Zusätzlich zu den Out-of-Process-LPC-Aufrufen an CSRSSXP und höher erfolgt ein Out-of-Process-Aufruf an die Anwendungskompatibilitäts-Engine, um das Programm in der Anwendungskompatibilitätsdatenbank zu finden. Dieser Schritt verursacht genügend Overhead, sodass Microsoft eine Gruppenrichtlinienoption bereitstellt, um die Kompatibilitätsengine auf WS2003 aus Leistungsgründen zu deaktivieren .

Die Win32-Laufzeitbibliotheken (kernel32.dll usw.) führen beim Start auch viele Registrierungslesevorgänge und -initialisierungen durch, die nicht für UNIX-, SFU- oder native Prozesse gelten.

Native Prozesse (ohne Umgebungssubsystem) lassen sich sehr schnell erstellen. SFU leistet bei der Prozesserstellung viel weniger als Win32, sodass die Prozesse auch schnell erstellt werden können.

UPDATE FÜR 2019: LXSS: Windows Subsystem für Linux hinzufügen

Das Ersetzen von SFU für Windows 10 ist das LXSS-Umgebungssubsystem. Es ist 100% Kernel-Modus und erfordert keinen der IPCs, die Win32 weiterhin hat. Syscall für diese Prozesse ist direkt an lxss.sys / lxcore.sys gerichtet, sodass der fork () - oder andere Prozess, der einen Anruf erstellt, nur 1 Systemaufruf für den Ersteller kostet. [Ein Datenbereich namens Instanz] verfolgt alle LX-Prozesse, Threads und den Laufzeitstatus.

LXSS-Prozesse basieren auf nativen Prozessen, nicht auf Win32-Prozessen. Alle Win32-spezifischen Dinge wie die Kompatibilitäts-Engine sind überhaupt nicht aktiviert.


16

Neben der Antwort von Rob Walker: Heutzutage gibt es Dinge wie die native POSIX-Thread-Bibliothek - wenn Sie möchten. Lange Zeit war die einzige Möglichkeit, die Arbeit in der Unix-Welt zu "delegieren", die Verwendung von fork () (und dies wird unter vielen, vielen Umständen immer noch bevorzugt). zB eine Art Socket-Server

socket_accept ()
Gabel()
if (Kind)
    handleRequest ()
sonst
    goOnBeingParent ()
Daher musste die Implementierung von Fork schnell sein und im Laufe der Zeit wurden viele Optimierungen implementiert. Microsoft hat CreateThread oder sogar Fasern empfohlen, anstatt neue Prozesse und die Verwendung der Interprozesskommunikation zu erstellen. Ich denke, es ist nicht "fair", CreateProcess mit Fork zu vergleichen, da sie nicht austauschbar sind. Es ist wahrscheinlich besser, fork / exec mit CreateProcess zu vergleichen.


2
Zu Ihrem letzten Punkt: fork () ist nicht mit CreateProcess () austauschbar, aber man kann auch sagen, dass Windows dann fork () implementieren sollte, da dies mehr Flexibilität bietet.
Blaisorblade

Ah, das Verb To Bee.
Acib708

Aber Fork + Exec unter Linux ist unter MS-Windows schneller als CreateThread. Und Linux kann selbstständig arbeiten, um noch schneller zu sein. Wie auch immer Sie es vergleichen, MS ist langsamer.
Strg-Alt-Delor

13

Der Schlüssel zu dieser Angelegenheit ist meiner Meinung nach die historische Nutzung beider Systeme. Windows (und DOS davor) haben ursprünglich Einplatzsysteme für gewesen persönlichen Computer. Daher müssen diese Systeme normalerweise nicht ständig viele Prozesse erstellen. (sehr) einfach ausgedrückt, ein Prozess wird nur erstellt, wenn dieser eine einsame Benutzer ihn anfordert (und wir Menschen arbeiten relativ gesehen nicht sehr schnell).

Unix-basierte Systeme waren ursprünglich Mehrbenutzersysteme und Server. Insbesondere für letztere ist es nicht ungewöhnlich, dass Prozesse (z. B. Mail- oder http-Daemons) Prozesse aufteilen, um bestimmte Jobs zu erledigen (z. B. die Pflege einer eingehenden Verbindung). Ein wichtiger Faktor dabei ist die kostengünstige forkMethode (die, wie von Rob Walker ( 47865 ) erwähnt, zunächst denselben Speicher für den neu erstellten Prozess verwendet), die sehr nützlich ist, da der neue Prozess sofort über alle erforderlichen Informationen verfügt.

Es ist klar, dass zumindest historisch gesehen die Notwendigkeit für Unix-basierte Systeme zur schnellen Prozesserstellung weitaus größer ist als für Windows-Systeme. Ich denke, dass dies immer noch der Fall ist, weil Unix-basierte Systeme immer noch sehr prozessorientiert sind, während Windows aufgrund seiner Geschichte wahrscheinlich stärker auf Threads ausgerichtet war (Threads sind nützlich, um reaktionsfähige Anwendungen zu erstellen).

Haftungsausschluss: Ich bin in dieser Angelegenheit kein Experte. Verzeihen Sie mir, wenn ich etwas falsch gemacht habe.


9

Äh, es scheint eine Menge Rechtfertigungen zu geben, die "so ist es besser".

Ich denke, die Leute könnten vom Lesen von "Showstopper" profitieren. das Buch über die Entwicklung von Windows NT.

Der ganze Grund, warum die Dienste unter Windows NT als DLLs in einem Prozess ausgeführt werden, war, dass sie als separate Prozesse zu langsam waren.

Wenn Sie sich schmutzig gemacht haben, werden Sie feststellen, dass die Strategie zum Laden der Bibliothek das Problem ist.

Auf Unices (im Allgemeinen) werden die Codesegmente der Shared Libraries (DLLs) tatsächlich gemeinsam genutzt.

Windows NT lädt eine Kopie der DLL pro Prozess, da es das Bibliothekscodesegment (und das ausführbare Codesegment) nach dem Laden manipuliert. (Sagt es, wo sind Ihre Daten?)

Dies führt zu Codesegmenten in Bibliotheken, die nicht wiederverwendbar sind.

Das Erstellen des NT-Prozesses ist also ziemlich teuer. Und auf der anderen Seite bedeutet dies, dass DLL keine nennenswerte Speicherersparnis darstellt, sondern eine Chance für Abhängigkeitsprobleme zwischen Apps darstellt.

Manchmal lohnt es sich in der Technik, zurückzutreten und zu sagen: "Wenn wir das jetzt so gestalten würden, dass es wirklich scheiße ist, wie würde es dann aussehen?"

Ich arbeitete mit einem eingebetteten System, das einst ziemlich temperamentvoll war, und eines Tages schaute ich es mir an und stellte fest, dass es sich um ein Hohlraummagnetron handelte, mit der Elektronik im Mikrowellenhohlraum. Danach haben wir es viel stabiler (und weniger wie eine Mikrowelle) gemacht.


3
Codesegmente können wiederverwendet werden, solange die DLL an ihrer bevorzugten Basisadresse geladen wird. Traditionell sollten Sie sicherstellen, dass Sie nicht widersprüchliche Basisadressen für alle DLLs festlegen, die in Ihre Prozesse geladen werden, aber mit ASLR nicht funktionieren.
Mike Dimmick

Es gibt ein Tool, mit dem alle DLLs neu gestartet werden können, nicht wahr? Ich bin mir nicht sicher, was es mit ASLR macht.
Zan Lynx

3
Die Freigabe von Codeabschnitten funktioniert auch auf ASLR-fähigen Systemen.
Johannes vorbei

@MikeDimmick, damit jeder, der eine DLL erstellt, zusammenarbeiten muss, um sicherzustellen, dass keine Konflikte auftreten, oder patchen Sie sie alle auf Systemebene, bevor Sie sie laden?
Strg-Alt-Delor

9

Die kurze Antwort lautet "Softwareschichten und -komponenten".

Die Windows-SW-Architektur verfügt über einige zusätzliche Ebenen und Komponenten, die unter Unix nicht vorhanden sind oder unter Unix im Kernel vereinfacht und verarbeitet werden.

Unter Unix sind Fork und Exec direkte Aufrufe des Kernels.

Unter Windows wird die Kernel-API nicht direkt verwendet, darüber befinden sich Win32 und bestimmte andere Komponenten. Daher muss die Prozesserstellung zusätzliche Ebenen durchlaufen und der neue Prozess muss gestartet werden oder eine Verbindung zu diesen Ebenen und Komponenten herstellen.

Seit geraumer Zeit versuchen Forscher und Unternehmen, Unix auf vage ähnliche Weise aufzubrechen, wobei ihre Experimente normalerweise auf dem Mach-Kernel basieren . ein bekanntes Beispiel ist OS X . Jedes Mal, wenn sie es versuchen, wird es jedoch so langsam, dass sie die Teile zumindest teilweise entweder dauerhaft oder für Produktionslieferungen wieder teilweise in den Kernel zurückführen.


Ebenen verlangsamen nicht unbedingt die Dinge: Ich habe einen Gerätetreiber mit vielen Ebenen in C geschrieben. Sauberer Code, gute Programmierung, einfach zu lesen. Es war schneller (geringfügig) als eine Version, die in einem hochoptimierten Assembler ohne Ebenen geschrieben wurde.
Strg-Alt-Delor

Die Ironie ist, dass NT ein riesiger Kernel ist (kein Mikrokernel)
Strg-Alt-Delor

2

Da es in einigen Antworten eine Rechtfertigung für MS-Windows zu geben scheint, z

  • „NT-Kernel und Win32 sind nicht dasselbe. Wenn Sie auf den NT-Kernel programmieren, ist das nicht so schlimm. “- Stimmt, aber wenn Sie kein Posix-Subsystem schreiben, wen interessiert das dann? Sie werden an win32 schreiben.
  • „Es ist nicht fair, Gabel mit ProcessCreate zu vergleichen, da sie verschiedene Dinge tun und Windows keine Gabel hat.“ - Stimmt, also werde ich Gleiches mit Gleichem vergleichen. Ich werde jedoch auch Fork vergleichen, da es viele Anwendungsfälle gibt, wie z. B. die Prozessisolierung (z. B. wird jeder Tab eines Webbrowsers in einem anderen Prozess ausgeführt).

Schauen wir uns nun die Fakten an. Was ist der Unterschied in der Leistung?

Daten zusammengefasst von http://www.bitsnbites.eu/benchmarking-os-primitives/ .
Da Voreingenommenheit unvermeidlich ist, habe ich es für die meisten Tests i7 8 Core 3.2GHz zugunsten von MS-Windows-
Hardware getan. Außer Raspberry-Pi mit Gnu / Linux

Ein Vergleich verschiedener grundlegender Vorgänge unter Gnu / Linux, Apple-Mac und Microsoft Windows (kleiner ist besser)

Ein Vergleich von MS-Windows-Prozess erstellen mit Linux

Hinweise: Unter Linux forkist die von MS-Window bevorzugte Methode schneller CreateThread.

Zahlen für Operationen zur Erstellung von Prozessen (da der Wert für Linux in der Tabelle nur schwer zu erkennen ist).

In der Reihenfolge der Geschwindigkeit am schnellsten bis am langsamsten (Zahlen sind Zeit, klein ist besser).

  • Linux CreateThread 12
  • Mac CreateThread 15
  • Linux Fork 19
  • Windows CreateThread 25
  • Linux CreateProcess (fork + exec) 45
  • Mac Fork 105
  • Mac CreateProcess (fork + exec) 453
  • Raspberry-Pi CreateProcess (Gabel + Exec) 501
  • Windows CreateProcess 787
  • Windows CreateProcess Mit Virenscanner 2850
  • Windows Fork (simulieren mit CreateProcess + Fixup) größer als 2850

Zahlen für andere Messungen

  • Eine Datei erstellen.
    • Linux 13
    • Mac 113
    • Windows 225
    • Raspberry-Pi (mit langsamer SD-Karte) 241
    • Windows mit Defender und Virenscanner usw. 12950
  • Speicher zuordnen
    • Linux 79
    • Windows 93
    • Mac 152

1

All das und die Tatsache, dass auf dem Win-Computer höchstwahrscheinlich eine Antivirensoftware während des Erstellungsprozesses aktiviert wird ... Das ist normalerweise die größte Verlangsamung.


1
Ja, es ist die größte, aber nicht die einzige signifikante Verlangsamung.
Strg-Alt-Delor

1

Es ist auch erwähnenswert, dass das Sicherheitsmodell in Windows erheblich komplizierter ist als in Unix-basierten Betriebssystemen, was bei der Prozesserstellung viel Aufwand verursacht. Ein weiterer Grund, warum Multithreading in Windows dem Multiprozessing vorgezogen wird.


1
Ich würde erwarten, dass ein komplizierteres Sicherheitsmodell sicherer ist. aber die Fakten zeigen etwas anderes.
Lie Ryan

4
SELinux ist auch ein sehr komplexes Sicherheitsmodell, und es bedeutet keinen nennenswerten Overhead fürfork()
Spudd86

6
@LieRyan, Im Software-Design (meiner Erfahrung nach) bedeutet komplizierter sehr selten sicherer.
Woodrow Douglass
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.