Pourquoi créer un nouveau processus est-il plus cher sous Windows que Linux?

101

J'ai entendu dire que créer un nouveau processus sur une machine Windows coûte plus cher que sur Linux. Est-ce vrai? Quelqu'un peut-il expliquer les raisons techniques pour lesquelles il est plus cher et fournir des raisons historiques pour les décisions de conception derrière ces raisons?

Lecture seulement
la source

Réponses:

68

mweerden: NT a été conçu pour les utilisateurs multiples dès le premier jour, ce n'est donc pas vraiment une raison. Cependant, vous avez raison sur le fait que la création de processus joue un rôle moins important sur NT que sur Unix car NT, contrairement à Unix, favorise le multithreading par rapport au multitraitement.

Rob, il est vrai que fork est relativement bon marché lorsque COW est utilisé, mais en fait, fork est principalement suivi par un exécutant. Et un exécuteur doit également charger toutes les images. Discuter des performances de la fourche n'est donc qu'une partie de la vérité.

Lorsque vous discutez de la vitesse de création des processus, il est probablement judicieux de faire la distinction entre NT et Windows / Win32. En ce qui concerne NT (c'est-à-dire le noyau lui-même), je ne pense pas que la création de processus (NtCreateProcess) et la création de thread (NtCreateThread) soient significativement plus lentes que sur Unix moyen. Il se peut qu'il y en ait un peu plus, mais je ne vois pas ici la raison principale de la différence de performance.

Si vous regardez Win32, cependant, vous remarquerez qu'il ajoute un peu de surcharge au processus de création. D'une part, il faut que le CSRSS soit informé de la création de processus, ce qui implique LPC. Il nécessite au moins kernel32 pour être chargé en plus, et il doit effectuer un certain nombre d'éléments de travail de comptabilité supplémentaires à effectuer avant que le processus soit considéré comme un processus Win32 à part entière. Et n'oublions pas toute la surcharge supplémentaire imposée par l'analyse des manifestes, la vérification si l'image nécessite un shim de compatibilité, la vérification de l'application des politiques de restriction logicielle, yada yada.

Cela dit, je vois le ralentissement général dans la somme de toutes ces petites choses qui doivent être faites en plus de la création brute d'un processus, d'un espace VA et d'un thread initial. Mais comme dit au début - en raison de la préférence du multithreading au multitâche, le seul logiciel sérieusement affecté par cette dépense supplémentaire est un logiciel Unix mal porté. Bien que cette situation change lorsque des logiciels comme Chrome et IE8 redécouvrent soudainement les avantages du multitraitement et commencent à fréquemment démarrer et démonter des processus ...

Johannes qui passe
la source
8
Fork n'est pas toujours suivi par exec (), et les gens se soucient uniquement de fork (). Apache 1.3 utilise fork () (sans exec) sur Linux et des threads sur Windows, même si dans de nombreux cas les processus sont forkés avant d'être nécessaires et conservés dans un pool.
Blaisorblade
5
Sans oublier bien sûr la commande 'vfork', qui est conçue pour le scénario 'juste appeler exec' que vous décrivez.
Chris Huang-Leaver
4
Un autre type de logiciel qui est sérieusement affecté par cela est tout type de script shell qui implique la coordination de plusieurs processus. Les scripts Bash dans Cygwin, par exemple, en souffrent grandement. Considérez une boucle shell qui génère beaucoup de sed, awk et grep dans les pipelines. Chaque commande génère un processus et chaque canal génère un sous-shell et un nouveau processus dans ce sous-shell. Unix a été conçu avec ce type d'utilisation à l'esprit, c'est pourquoi la création de processus rapide reste la norme là-bas.
Dan Moulding
5
-1. L'affirmation selon laquelle les logiciels sont «mal portés» parce qu'ils ne fonctionnent pas bien sur un système d'exploitation mal conçu et plein de compatibilité qui ralentit la création de processus est ridicule.
Miles Rout
6
@MilesRout l'objectif du portage est de modifier le logiciel pour qu'il s'exécute sur un nouveau système cible, en gardant à l'esprit les points forts et les inconvénients de ce système. Peu performants logiciels portés est mal logiciels portés, quels que soient les obstacles du système d'exploitation fournit.
Dizzyspiral
28

Unix a un appel système 'fork' qui 'divise' le processus courant en deux, et vous donne un second processus identique au premier (modulo le retour de l'appel fork). Étant donné que l'espace d'adressage du nouveau processus est déjà opérationnel, cela devrait coûter moins cher que d'appeler `` CreateProcess '' dans Windows et de le charger de l'image exe, des dll associées, etc.

Dans le cas de la fourche, le système d'exploitation peut utiliser la sémantique «copie sur écriture» pour les pages mémoire associées aux deux nouveaux processus afin de s'assurer que chacun obtient sa propre copie des pages qu'il modifie par la suite.

Rob Walker
la source
22
Cet argument ne tient que lorsque vous bifurquez vraiment. Si vous démarrez un nouveau processus, sous Unix, vous devez toujours fork et exécuter. Windows et Unix ont une copie en écriture. Windows réutilisera certainement un EXE chargé si vous exécutez une deuxième copie d'une application. Je ne pense pas que votre explication soit correcte, désolé.
Joel Spolsky
1
Plus d'informations sur exec () et fork () vipinkrsahu.blogspot.com/search/label/system%20programming
webkul
J'ai ajouté des données de performance dans ma réponse. stackoverflow.com/a/51396188/537980 Vous pouvez voir que c'est plus rapide.
ctrl-alt-delor
25

Ajoutant à ce que JP a dit: la plupart des frais généraux appartiennent au démarrage de Win32 pour le processus.

Le noyau Windows NT prend en charge la fourche COW. SFU (l'environnement UNIX de Microsoft pour Windows) les utilise. Cependant, Win32 ne prend pas en charge le fork. Les processus SFU ne sont pas des processus Win32. SFU est orthogonal à Win32: ce sont tous les deux des sous-systèmes d'environnement construits sur le même noyau.

En plus des appels LPC hors processus à CSRSS, dans XP et versions ultérieures, il existe un appel hors processus au moteur de compatibilité des applications pour trouver le programme dans la base de données de compatibilité des applications. Cette étape entraîne une surcharge suffisante pour que Microsoft propose une option de stratégie de groupe pour désactiver le moteur de compatibilité sur WS2003 pour des raisons de performances.

Les bibliothèques d'exécution Win32 (kernel32.dll, etc.) effectuent également de nombreuses lectures de registre et d'initialisation au démarrage qui ne s'appliquent pas aux processus UNIX, SFU ou natifs.

Les processus natifs (sans sous-système d'environnement) sont très rapides à créer. SFU fait beaucoup moins que Win32 pour la création de processus, donc ses processus sont également rapides à créer.

MISE À JOUR POUR 2019: ajouter LXSS: sous-système Windows pour Linux

Le sous-système d'environnement LXSS est le remplacement de SFU pour Windows 10. Il est en mode noyau à 100% et ne nécessite aucun de cet IPC que Win32 continue d'avoir. Syscall pour ces processus est dirigé directement vers lxss.sys / lxcore.sys, donc le fork () ou tout autre processus de création d'appel ne coûte qu'un seul appel système pour le créateur, au total. [Une zone de données appelée l'instance] assure le suivi de tous les processus LX, threads et état d'exécution.

Les processus LXSS sont basés sur des processus natifs et non sur des processus Win32. Tous les éléments spécifiques à Win32 comme le moteur de compatibilité ne sont pas du tout engagés.

Chris Smith
la source
16

En plus de la réponse de Rob Walker: De nos jours, vous avez des choses comme la bibliothèque de threads POSIX natifs - si vous le souhaitez. Mais pendant longtemps, la seule façon de "déléguer" le travail dans le monde Unix était d'utiliser fork () (et c'est toujours préférable dans de très nombreuses circonstances). par exemple une sorte de serveur socket

socket_accept ()
fourchette()
si (enfant)
    handleRequest ()
autre
    goOnBeingParent ()
Par conséquent, la mise en œuvre de fork devait être rapide et de nombreuses optimisations ont été mises en œuvre au fil du temps. Microsoft a approuvé CreateThread ou même des fibres au lieu de créer de nouveaux processus et d'utiliser la communication interprocessus. Je pense que ce n'est pas "juste" de comparer CreateProcess à fork car ils ne sont pas interchangeables. Il est probablement plus approprié de comparer fork / exec à CreateProcess.

VolkerK
la source
2
À propos de votre dernier point: fork () n'est pas échangeable avec CreateProcess (), mais on peut aussi dire que Windows devrait alors implémenter fork (), car cela donne plus de flexibilité.
Blaisorblade
Ah, le verbe To Bee.
acib708 du
Mais fork + exec sous Linux est plus rapide que CreateThread sur MS-Windows. Et Linux peut faire un fork de lui-même pour être encore plus rapide. Cependant, vous le comparez, MS est plus lent.
ctrl-alt-delor
13

La clé de cette question est l'utilisation historique des deux systèmes, je pense. Windows (et DOS avant cela) étaient à l'origine des systèmes mono-utilisateur pour ordinateurs personnels . En tant que tels, ces systèmes n'ont généralement pas besoin de créer beaucoup de processus tout le temps; (très) simplement, un processus n'est créé que lorsque cet utilisateur solitaire le demande (et nous, les humains, n'opérons pas très vite, relativement parlant).

Les systèmes basés sur Unix étaient à l'origine des systèmes et des serveurs multi-utilisateurs. Surtout pour ces derniers, il n'est pas rare d'avoir des processus (par exemple des démons mail ou http) qui séparent les processus pour gérer des tâches spécifiques (par exemple, s'occuper d'une connexion entrante). Un facteur important pour ce faire est la forkméthode bon marché (qui, comme mentionné par Rob Walker ( 47865 ), utilise initialement la même mémoire pour le processus nouvellement créé) qui est très utile car le nouveau processus a immédiatement toutes les informations dont il a besoin.

Il est clair qu'au moins historiquement, la nécessité pour les systèmes Unix d'avoir une création de processus rapide est bien plus grande que pour les systèmes Windows. Je pense que c'est toujours le cas parce que les systèmes basés sur Unix sont toujours très orientés processus, tandis que Windows, en raison de son histoire, a probablement été plus orienté thread (les threads étant utiles pour créer des applications responsives).

Avertissement: je ne suis en aucun cas un expert en la matière, alors pardonnez-moi si je me suis trompé.

mweerden
la source
9

Euh, il semble y avoir beaucoup de justification "c'est mieux comme ça".

Je pense que les gens pourraient bénéficier de la lecture de "Showstopper"; le livre sur le développement de Windows NT.

La raison pour laquelle les services s'exécutent en tant que DLL dans un processus sous Windows NT était qu'ils étaient trop lents en tant que processus séparés.

Si vous vous salissez, vous constaterez que la stratégie de chargement de la bibliothèque est le problème.

Sur les Unices (en général), les segments de code des bibliothèques partagées (DLL) sont en fait partagés.

Windows NT charge une copie de la DLL par processus, car il manipule le segment de code de la bibliothèque (et le segment de code exécutable) après le chargement. (Lui dit où sont vos données?)

Cela se traduit par des segments de code dans les bibliothèques qui ne sont pas réutilisables.

Ainsi, le processus NT créé est en fait assez coûteux. Et du côté négatif, cela ne permet pas à la DLL d'économiser de la mémoire, mais une chance de problèmes de dépendance inter-applications.

Parfois, il est payant en ingénierie de prendre du recul et de dire: "maintenant, si nous devions concevoir cela vraiment nul, à quoi cela ressemblerait-il?"

J'ai travaillé avec un système embarqué qui était assez capricieux une fois, et un jour je l'ai regardé et j'ai réalisé qu'il s'agissait d'un magnétron à cavité, avec l'électronique dans la cavité micro-ondes. Nous l'avons rendu beaucoup plus stable (et moins comme un micro-ondes) par la suite.

Tim Williscroft
la source
3
Les segments de code sont réutilisables tant que la DLL se charge à son adresse de base préférée. En règle générale, vous devez vous assurer de définir des adresses de base non conflictuelles pour toutes les DLL qui se chargeraient dans vos processus, mais cela ne fonctionne pas avec ASLR.
Mike Dimmick
Il existe un outil pour rebaser toutes les DLL, n'est-ce pas? Je ne sais pas ce qu'il fait avec ASLR.
Zan Lynx
3
Le partage de sections de code fonctionne également sur les systèmes compatibles ASLR.
Johannes passant
@MikeDimmick donc tout le monde, qui crée une DLL doit coopérer, pour s'assurer qu'il n'y a pas de conflits, ou les corrigez-vous tous au niveau du système, avant le chargement?
ctrl-alt-delor
9

La réponse courte est "couches et composants logiciels".

L'architecture Windows SW a quelques couches et composants supplémentaires qui n'existent pas sous Unix ou qui sont simplifiés et gérés à l'intérieur du noyau sous Unix.

Sous Unix, fork et exec sont des appels directs au noyau.

Sous Windows, l'API du noyau n'est pas utilisée directement, il y a win32 et certains autres composants en plus, donc la création de processus doit passer par des couches supplémentaires, puis le nouveau processus doit démarrer ou se connecter à ces couches et composants.

Pendant un certain temps, les chercheurs et les entreprises ont tenté de briser Unix d'une manière vaguement similaire, en basant généralement leurs expériences sur le noyau Mach ; un exemple bien connu est OS X .. Chaque fois qu'ils essaient, cependant, cela devient si lent qu'ils finissent par fusionner au moins partiellement les pièces dans le noyau, soit de manière permanente, soit pour des expéditions de production.

DigitalRoss
la source
Les couches ne ralentissent pas nécessairement les choses: j'ai écrit un pilote de périphérique, avec beaucoup de couches, en C. Code propre, programmation littéraire, facile à lire. C'était plus rapide (marginalement) qu'une version écrite en assembleur hautement optimisé, sans couches.
ctrl-alt-delor
L'ironie est que NT est un énorme noyau (pas un micro noyau)
ctrl-alt-delor
2

Comme il semble y avoir une justification de MS-Windows dans certaines des réponses, par exemple

  • «Le noyau NT et Win32 ne sont pas la même chose. Si vous programmez sur le noyau NT, alors ce n'est pas si mal »- C'est vrai, mais à moins que vous n'écriviez un sous-système Posix, alors peu importe. Vous allez écrire à win32.
  • "Il n'est pas juste de comparer fork, avec ProcessCreate, car ils font des choses différentes, et Windows n'a pas de fork" - C'est vrai, donc je vais comparer comme avec comme. Cependant, je comparerai également fork, car il a de nombreux cas d'utilisation, tels que l'isolation de processus (par exemple, chaque onglet d'un navigateur Web fonctionne dans un processus différent).

Regardons maintenant les faits, quelle est la différence de performance?

Données synthétisées à partir de http://www.bitsnbites.eu/benchmarking-os-primitives/ .
Parce que le biais est inévitable, en résumé, je l'ai fait en faveur du matériel MS-Windows
pour la plupart des tests i7 8 core 3.2GHz. Sauf Raspberry-Pi exécutant Gnu / Linux

Une comparaison de diverses opérations de base, sur Gnu / Linux, Apple-Mac et Microsoft Windows (plus petit est mieux)

Une comparaison entre la création de processus MS-Windows et Linux

Remarques: Sous Linux, forkest plus rapide que la méthode préférée de MS-Window CreateThread.

Chiffres pour les opérations de type création de processus (car il est difficile de voir la valeur pour Linux dans le graphique).

Par ordre de vitesse, du plus rapide au plus lent (les nombres sont le temps, petit est meilleur).

  • 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 (fourche + exécutable) 501
  • Windows CreateProcess 787
  • Windows CreateProcess avec antivirus 2850
  • Windows Fork (simuler avec CreateProcess + fixup) supérieur à 2850

Numéros pour d'autres mesures

  • Créer un fichier.
    • Linux 13
    • Mac 113
    • Windows 225
    • Raspberry-Pi (avec carte SD lente) 241
    • Windows avec défenseur et antivirus, etc. 12950
  • Allouer de la mémoire
    • Linux 79
    • Windows 93
    • Mac 152
ctrl-alt-delor
la source
1

Tout cela en plus, il y a le fait que sur la machine Win, un logiciel antivirus se déclenchera très probablement pendant le CreateProcess ... C'est généralement le plus gros ralentissement.

Gabr
la source
1
Oui, c'est le plus gros ralentissement, mais pas le seul.
ctrl-alt-delor
1

Il convient également de noter que le modèle de sécurité sous Windows est beaucoup plus compliqué que dans les systèmes d'exploitation basés sur unix, ce qui ajoute beaucoup de temps système lors de la création du processus. Encore une autre raison pour laquelle le multithreading est préféré au multitraitement sous Windows.

hacksoncode
la source
1
Je m'attendrais à ce qu'un modèle de sécurité plus complexe soit plus sûr; mais les faits montrent le contraire.
Lie Ryan
4
SELinux est également un modèle de sécurité très complexe, et il n'impose pas de surcharge importantefork()
Spudd86
6
@LieRyan, Dans la conception de logiciels (d'après mon expérience), plus compliqué signifie très rarement plus sécurisé.
Woodrow Douglass