web-dev-qa-db-fra.com

Techniquement, pourquoi les processus dans Erlang sont-ils plus efficaces que les threads OS?

Caractéristiques d'Erlang

De Programmation Erlang (2009):

La simultanéité Erlang est rapide et évolutive. Ses processus sont légers dans la mesure où la machine virtuelle Erlang ne crée pas de thread OS pour chaque processus créé. Ils sont créés, planifiés et gérés dans la machine virtuelle, indépendamment du système d'exploitation sous-jacent. Par conséquent, le temps de création de processus est de l'ordre des microsecondes et indépendant du nombre de processus existants simultanément. Comparez cela avec Java et C #, où pour chaque processus un thread OS sous-jacent est créé: vous obtiendrez des comparaisons très compétitives, avec Erlang surpassant considérablement les deux langages.

De Programmation orientée concurrence à Erlang (pdf)(slides) (2003):

Nous observons que le temps nécessaire pour créer un processus Erlang est constant de 1µs à 2500 processus; par la suite, il augmente à environ 3 µs pour jusqu'à 30 000 processus. Les performances de Java et C # sont indiquées en haut de la figure. Pour un petit nombre de processus, il faut environ 300µs pour créer un processus. Créer plus de deux mille processus est impossible.

Nous voyons que jusqu'à 30 000 processus, le temps nécessaire pour envoyer un message entre deux processus Erlang est d'environ 0,8 µs. Pour C #, il faut environ 50µs par message, jusqu'au nombre maximum de processus (qui était d'environ 1800 processus). Java était encore pire, pour jusqu'à 100 processus, il fallait environ 50µs par message par la suite, il augmentait rapidement à 10 ms par message quand il y avait environ 1000 Java processus.

Mes pensées

Je ne comprends pas complètement techniquement pourquoi les processus Erlang sont tellement plus efficaces pour générer de nouveaux processus et ont des empreintes mémoire beaucoup plus petites par processus. Le système d'exploitation et Erlang VM doivent effectuer la planification, les changements de contexte et garder une trace des valeurs dans les registres, etc.).

Pourquoi les threads OS ne sont-ils pas implémentés de la même manière que les processus dans Erlang? Doivent-ils soutenir quelque chose de plus? Et pourquoi ont-ils besoin d'une plus grande empreinte mémoire? Et pourquoi ont-ils un frai et une communication plus lents?

Techniquement, pourquoi les processus dans Erlang sont-ils plus efficaces que les threads d'OS en termes de génération et de communication? Et pourquoi les threads dans le système d'exploitation ne peuvent-ils pas être implémentés et gérés de la même manière efficace? Et pourquoi les threads du système d'exploitation ont-ils une plus grande empreinte mémoire, ainsi qu'une génération et une communication plus lentes?

Plus de lecture

164
Jonas

Il y a plusieurs facteurs contributifs:

  1. Les processus Erlang ne sont pas des processus OS. Ils sont implémentés par Erlang VM utilisant un modèle de thread coopératif léger (préemptif au niveau Erlang, mais sous le contrôle d'un runtime planifié en coopération). Cela signifie qu'il est beaucoup moins cher de changer de contexte , car ils ne commutent qu'à des points connus et contrôlés et n'ont donc pas à enregistrer l'intégralité de l'état du processeur (normal, SSE et FPU, mappage de l'espace d'adressage, etc.).
  2. Les processus Erlang utilisent des piles allouées dynamiquement, qui commencent très petites et augmentent au besoin. Cela permet la génération de plusieurs milliers - voire de millions - de processus Erlang sans aspirer toute la mémoire RAM disponible.
  3. Erlang était un filetage unique, ce qui signifie qu'il n'était pas nécessaire d'assurer la sécurité du fil entre les processus. Il prend désormais en charge SMP, mais l'interaction entre les processus Erlang sur le même ordonnanceur/cœur est toujours très légère (il existe des files d'attente d'exécution distinctes par cœur).
105
Marcelo Cantos

Après quelques recherches supplémentaires, j'ai trouvé une présentation de Joe Armstrong.

De Erlang - logiciel pour un monde simultané (présentation) (à 13 min):

[Erlang] est un langage simultané - j'entends par là que les threads font partie du langage de programmation, ils n'appartiennent pas au système d'exploitation. C'est vraiment ce qui ne va pas avec les langages de programmation comme Java et C++. Ce ne sont pas les threads dans le langage de programmation, les threads sont quelque chose dans le système d'exploitation - et ils héritent de tous les problèmes qu'ils ont dans le Un des problèmes est la granularité du système de gestion de la mémoire.La gestion de la mémoire dans le système d'exploitation protège des pages entières de mémoire, donc la plus petite taille qu'un thread peut être est la plus petite taille d'une page.C'est en fait trop gros.

Si vous ajoutez plus de mémoire à votre machine - vous avez le même nombre de bits qui protège la mémoire de sorte que la granularité des tables de pages augmente - vous finissez par utiliser disons 64 Ko pour un processus que vous connaissez s'exécutant sur quelques centaines d'octets.

Je pense que ça répond sinon tous, au moins quelques-unes de mes questions

65
Jonas

J'ai implémenté des coroutines dans l'assembleur et mesuré les performances.

La commutation entre coroutines, processus Erlang alias, prend environ 16 instructions et 20 nanosecondes sur un processeur moderne. En outre, vous connaissez souvent le processus vers lequel vous basculez (exemple: un processus recevant un message dans sa file d'attente peut être implémenté comme un transfert direct du processus appelant au processus de réception) de sorte que le planificateur n'entre pas en jeu, ce qui rend c'est une opération O(1).

Pour basculer entre les threads du système d'exploitation, il faut environ 500 à 1 000 nanosecondes, car vous appelez le noyau. Le planificateur de thread du système d'exploitation peut s'exécuter dans O(log(n)) ou O(log(log(n))) heure, qui commencera à être perceptible si vous avez des dizaines de milliers, voire des millions de threads.

Par conséquent, les processus Erlang sont plus rapides et évoluent mieux, car à la fois l'opération fondamentale de commutation est plus rapide et le planificateur s'exécute moins souvent.

44
Surfer Jeff

Les processus Erlang correspondent (approximativement) à fils verts dans d'autres langues; il n'y a pas de séparation imposée par le système d'exploitation entre les processus. (Il peut y avoir une séparation forcée par la langue, mais c'est une protection moindre malgré Erlang qui fait un meilleur travail que la plupart.) Parce qu'ils sont beaucoup plus légers, ils peuvent être utilisés beaucoup plus largement.

Les threads du système d'exploitation, d'autre part, peuvent être simplement planifiés sur différents cœurs de processeur et sont (principalement) capables de prendre en charge un traitement indépendant lié au processeur. Les processus OS sont comme des threads OS, mais avec une séparation renforcée par le système d'exploitation beaucoup plus forte. Le prix de ces capacités est que les threads d'OS et (encore plus) les processus sont plus chers.


Voici une autre façon de comprendre la différence. Supposons que vous alliez écrire une implémentation d'Erlang au-dessus de la JVM (pas une suggestion particulièrement folle), alors vous feriez de chaque processus Erlang un objet avec un certain état. Vous auriez alors un pool d'instances de Thread (généralement dimensionnées en fonction du nombre de cœurs dans votre système hôte; c'est un paramètre ajustable dans les vrais temps d'exécution Erlang BTW) qui exécutent les processus Erlang. À son tour, cela répartira le travail à effectuer sur les ressources système réelles disponibles. C'est une façon assez soignée de faire les choses, mais repose complètement sur le fait que chaque processus Erlang individuel ne fait pas grand-chose. C'est OK bien sûr; Erlang est structuré pour ne pas exiger que ces processus individuels soient lourds car c'est l'ensemble de ceux-ci qui exécute le programme.

À bien des égards, le vrai problème est celui de la terminologie. Les choses qu'Erlang appelle des processus (et qui correspondent fortement au même concept dans CSP, CCS, et en particulier le π-calcul) ne sont tout simplement pas les mêmes que les choses que les langages avec un héritage C (y compris C++, Java, C # et beaucoup d'autres) appellent un processus ou un thread. Il existe quelques similitudes (toutes impliquent une certaine notion d'exécution simultanée) mais il n'y a certainement aucune équivalence. Soyez donc prudent lorsque quelqu'un vous dit "processus"; ils pourraient comprendre que cela signifie quelque chose de complètement différent…

32
Donal Fellows

Je pense que Jonas voulait des chiffres sur la comparaison des threads OS aux processus Erlang. L'auteur de Programming Erlang, Joe Armstrong, a testé il y a quelque temps la possibilité de faire évoluer les processus Erlang vers les threads du système d'exploitation. Il a écrit un simple serveur Web dans Erlang et l'a testé contre Apache multi-thread (car Apache utilise des threads OS). Il y a un vieux site Web dont les données remontent à 1998. Je n'ai réussi à trouver ce site qu'une seule fois. Je ne peux donc pas fournir de lien. Mais l'information existe. Le point principal de l'étude a montré qu'Apache a atteint un maximum de moins de 8 Ko de processus, tandis que son serveur Erlang écrit à la main gérait 10 000+ processus.

2
Jurnell

Parce que l'interprète Erlang n'a qu'à se soucier de lui-même, le système d'exploitation a beaucoup d'autres choses à se soucier.

1
Francisco Soto

l'une des raisons pour lesquelles le processus erlang est créé non pas dans le système d'exploitation, mais dans l'evm (machine virtuelle erlang), donc le coût est plus faible.

0
ratzily