Meilleure réponse
La réponse à la question telle que posée est: cest la même chose que la différence entre « one « et » beaucoup « .
Mais je pense que ce que vous vouliez vraiment dire est quelque chose de plus comme ceci: en quoi les méthodologies de programmation diffèrent-elles pour la programmation dans un seul thread dans un seul processus par rapport à plusieurs threads dans un seul processus?
Des livres ont été écrits sur le sujet. Mais très brièvement, les différences sont toutes liées à un facteur: lors de la programmation dans un seul thread et processus, vous savez toujours comment vous êtes arrivé à linstruction actuelle. Les instructions se produisent en une seule séquence. Mais lors de la programmation pour de nombreux threads, vous ne savez pas quelles instructions ont été exécutées dans quel ordre pour accéder à linstruction courante. Cela rend la programmation plus compliquée.
Mais il y a un autre facteur qui la complique: contrairement aux processus, les threads partagent la mémoire. Vous ne savez pas quel thread a touché en dernier un emplacement mémoire donné, ou lequel sera le suivant, à moins davoir une sorte de « synchronisation ». Doù le mot-clé « synchronized » en Java (arraché à Ada). Moniteurs, sémaphores, verrous , les variables de condition et même le passage de messages ont tous été utilisés pour la synchronisation.
Réponse
(Mise à jour: faites attention à une autre réponse qui dit que vous ne pouvez pas avoir un serveur Web à thread unique qui gère bien les requêtes simultanées, car ce nest tout simplement pas vrai.)
Pourquoi un serveur Web multithread est-il meilleur quun serveur à thread unique? Ce nest pas le cas.
Il existe quatre manières de base pour un serveur Web de gérer la concurrence:
- forking un processus OS par requête (comme les anciennes versions dApache)
- engendrant un thread OS par requête (comme une nouvelle version dApache)
- en utilisant une boucle dévénement à thread unique (comme nginx )
- en utilisant des threads verts ou des processus légers planifié par un environnement dexécution de VM au lieu du système dexploitation (comme dans Erlang)
Actuellement, les approches les plus courantes sont les numéros 2 et 3.
Il existe des avantages et des inconvénients deux. Pour les opérations liées aux E / S (une caractéristique d’un serveur Web classique), vous obtenez de meilleures performances et nombre plus élevé de requêtes simultanées lorsque vous utilisez une boucle dévénements à thread unique . Mais l’inconvénient est que vous devez utiliser exclusivement des E / S non bloquantes asynchrones pour toutes les opérations, sinon vous bloquerez la boucle d’événements et perdrez des performances. Pour cette raison, il est plus facile de mettre en œuvre un serveur multithread mais vous payez en performances.
Pour les opérations liées au processeur (moins courantes pour un serveur Web habituel, peut-être plus courant pour une API à forte intensité de calcul), il est préférable davoir un thread ou processus OS par cœur . Cest facile à faire avec des boucles dévénements à un seul thread, car vous pouvez exécuter un cluster dun certain nombre de processus par cœur. Cest difficile à faire avec les serveurs multi-threads car si la création de threads est votre seul moyen de gérer les requêtes simultanées, vous ne pouvez pas vraiment contrôler le nombre de threads que vous aurez, car vous ne contrôlez pas le nombre de requêtes. Une fois que vous avez plus de threads que le nombre de cœurs de processeur, vous perdez les performances des commutateurs de contexte et vous utilisez également beaucoup de RAM.
Cest pourquoi un serveur nginx monothread fonctionne mieux quun serveur Web Apache multithread (et cest pourquoi nginx a été créé en premier lieu). Redis , une base de données réputée pour ses performances exceptionnellement élevées, est monothread .
Un exemple concret que je peux vous donner est celui-ci: Mon premier serveur web était Apache fonctionnant sur une machine Linux avec 500 Mo de RAM. Il créait un nouveau processus pour chaque requête (il y avait en fait un pool donc il ny avait pas beaucoup de forking impliqué, mais il devait garder ces processus en vie pour les réutiliser et les tuer de temps en temps pour éviter les fuites de ressources).
Mon système dexploitation utilisait environ 100 Mo de RAM. Chaque processus Apache utilise 20 Mo de RAM. Cela signifiait que mon serveur ne pouvait gérer que 20 requêtes simultanées et quil ny avait aucun moyen de contourner cela car je navais plus de RAM. Les processus étaient principalement bloqués sur les E / S, donc lutilisation du processeur était très faible, chaque demande au-dessus de ces 20 devait attendre et si ces 20 étaient par exemple. téléchargements de longue durée, mon serveur ne répondait absolument pas.
Lorsque le serveur Web nginx a été introduit, il utilisait une boucle dévénements à un seul thread et ne bloquait aucune requête. Il pourrait gérer beaucoup plus de requêtes simultanées, nayant aucun problème avec le mythique problème c10k – nginx a été essentiellement créé pour résoudre le problème c10k (10 000 requêtes simultanées).
Imaginez combien de RAM est gaspillée pour 10 000 threads si vous pourrait même engendrer autant et combien de temps est utilisé pour les changements de contexte.
Utilisation de la mémoire dApache multithread vs nginx monothread:
Incidemment, cest la raison pour laquelle Ryan Dahl a utilisé une E / S non bloquante et une boucle dévénement monothread dans Node.js et il utilise toujours la même idée dans Deno, parce que cest la manière décrire des serveurs réseau haute performance (contrairement à ce que vous pourriez lire dans dautres réponses ici).