J'ai récemment entendu quelques personnes dire que sous Linux, il est presque toujours préférable d'utiliser des processus plutôt que des threads, car Linux est très efficace dans la gestion des processus et parce qu'il y a tellement de problèmes (comme le verrouillage) associés aux threads. Cependant, je suis méfiant, car il semble que les threads pourraient donner un gain de performances assez important dans certaines situations.
Donc, ma question est la suivante: face à une situation que les threads et les processus peuvent tous les deux gérer assez bien, dois-je utiliser des processus ou des threads? Par exemple, si j'écrivais un serveur Web, devrais-je utiliser des processus ou des threads (ou une combinaison)?
linux
performance
multithreading
process
user17918
la source
la source
Réponses:
Linux utilise un modèle de thread 1-1, avec (pour le noyau) aucune distinction entre les processus et les threads - tout est simplement une tâche exécutable. *
Sous Linux, l'appel système
clone
clone une tâche, avec un niveau de partage configurable, parmi lesquels:CLONE_FILES
: partage la même table de descripteurs de fichiers (au lieu de créer une copie)CLONE_PARENT
: ne pas établir de relation parent-enfant entre la nouvelle tâche et l'ancienne (sinon, childgetppid()
= parent'sgetpid()
)CLONE_VM
: partager le même espace mémoire (au lieu de créer une copie COW )fork()
appelle leclone(
moins de partage)
etpthread_create()
appelle leclone(
plus de partage)
. **fork
ing coûte un tout petit peu pluspthread_create
qu'ing en raison de la copie des tables et de la création de mappages COW pour la mémoire, mais les développeurs du noyau Linux ont essayé (et réussi) à minimiser ces coûts.La commutation entre les tâches, si elles partagent le même espace mémoire et différentes tables, sera un peu moins chère que si elles ne sont pas partagées, car les données peuvent déjà être chargées dans le cache. Cependant, le changement de tâches est toujours très rapide même si rien n'est partagé - c'est autre chose que les développeurs du noyau Linux essaient d'assurer (et réussissent à assurer).
En fait, si vous êtes sur un système multiprocesseur, le non- partage peut en fait être bénéfique pour les performances: si chaque tâche s'exécute sur un processeur différent, la synchronisation de la mémoire partagée coûte cher.
* Simplifié.
CLONE_THREAD
provoque la distribution des signaux à partager (qui a besoinCLONE_SIGHAND
, qui partage la table de gestion des signaux).** Simplifié. Il existe à la fois
SYS_fork
etSYS_clone
syscalls, mais dans le noyau, lessys_fork
etsys_clone
sont à la fois des wrappers très fins autour de la mêmedo_fork
fonction, qui est elle-même un wrapper mincecopy_process
. Oui, les termesprocess
,thread
ettask
sont utilisés de manière plutôt interchangeable dans le noyau Linux ...la source
socket
,bind
,listen
,fork
, et ont de multiples processusaccept
connexions sur la même prise d'écoute. Un processus peut cesser d'accepter s'il est occupé, et le noyau acheminera les connexions entrantes vers un autre processus (si personne n'écoute, le noyau sera mis en file d'attente ou abandonné, en fonction dulisten
retard). Vous n'avez pas beaucoup plus de contrôle sur la répartition du travail que cela, mais c'est généralement suffisant!clone()
déterminer quelles ressources sont partagées. Une tâche peut égalementunshare()
ressources à tout moment ultérieur.task_struct
pour chaque tâche. Ceci est souvent appelé «processus» dans tout le code du noyau, mais il correspond à chaque thread exécutable. Il n'y a pasprocess_struct
; si un tas detask_struct
s sont liés entre eux par leurthread_group
liste, alors ils sont le même "processus" à l'espace utilisateur. Il y a un peu de gestion spéciale des "threads", par exemple tous les threads frères sont arrêtés sur fork et exec, et seul le thread "principal" apparaît dansls /proc
. Chaque thread est accessible via/proc/pid
cependant, qu'il soit répertorié/proc
ou non.clone(CLONE_THREAD | CLONE_VM | CLONE_SIGHAND))
vous donnerait un nouveau "thread" qui ne partage pas le répertoire de travail, les fichiers ou les verrous, tandisclone(CLONE_FILES | CLONE_FS | CLONE_IO)
que vous donnerait un "processus" qui le fait. Le système sous-jacent crée des tâches par clonage;fork()
et nepthread_create()
sont que des fonctions de bibliothèque qui invoquentclone()
différemment (comme je l'ai écrit dans cette réponse).Linux (et en effet Unix) vous offre une troisième option.
Option 1 - processus
Créez un exécutable autonome qui gère une partie (ou toutes les parties) de votre application, et invoquez-le séparément pour chaque processus, par exemple le programme exécute des copies de lui-même pour déléguer des tâches.
Option 2 - fils
Créez un exécutable autonome qui démarre avec un seul thread et créez des threads supplémentaires pour effectuer certaines tâches
Option 3 - fourche
Uniquement disponible sous Linux / Unix, c'est un peu différent. Un processus bifurqué est vraiment son propre processus avec son propre espace d'adressage - il n'y a rien que l'enfant puisse faire (normalement) pour affecter l'espace d'adressage de son parent ou de ses frères et sœurs (contrairement à un thread) - donc vous obtenez une robustesse supplémentaire.
Cependant, les pages mémoire ne sont pas copiées, elles sont copiées sur écriture, donc moins de mémoire est généralement utilisée que vous ne l'imaginez.
Considérez un programme de serveur Web qui se compose de deux étapes:
Si vous avez utilisé des threads, l'étape 1 serait effectuée une seule fois et l'étape 2 dans plusieurs threads. Si vous avez utilisé des processus "traditionnels", les étapes 1 et 2 devront être répétées pour chaque processus, et la mémoire pour stocker la configuration et les données d'exécution dupliquées. Si vous avez utilisé fork (), vous pouvez effectuer l'étape 1 une fois, puis fork (), en laissant les données d'exécution et la configuration en mémoire, intactes, non copiées.
Il y a donc vraiment trois choix.
la source
Cela dépend de nombreux facteurs. Les processus sont plus lourds que les threads et ont un coût de démarrage et d'arrêt plus élevé. La communication interprocessus (IPC) est également plus difficile et plus lente que la communication inter-fils.
Inversement, les processus sont plus sûrs et plus sécurisés que les threads, car chaque processus s'exécute dans son propre espace d'adressage virtuel. Si un processus se bloque ou a un dépassement de mémoire tampon, cela n'affecte aucun autre processus, alors que si un thread tombe en panne, il supprime tous les autres threads du processus et si un thread a un dépassement de mémoire tampon, il s'ouvre. un trou de sécurité dans tous les fils.
Donc, si les modules de votre application peuvent s'exécuter de manière indépendante avec peu de communication, vous devriez probablement utiliser des processus si vous pouvez vous permettre les coûts de démarrage et d'arrêt. Les performances d'IPC seront minimes et vous serez légèrement plus sûr contre les bugs et les failles de sécurité. Si vous avez besoin de toutes les performances que vous pouvez obtenir ou avoir beaucoup de données partagées (telles que des structures de données complexes), optez pour les threads.
la source
D'autres ont discuté des considérations.
Peut-être la différence importante est que dans Windows, les processus sont lourds et coûteux par rapport aux threads, et sous Linux, la différence est beaucoup plus petite, donc l'équation s'équilibre à un point différent.
la source
Il était une fois Unix et dans ce bon vieux Unix il y avait beaucoup de surcharge pour les processus, donc ce que certaines personnes intelligentes ont fait était de créer des threads, qui partageraient le même espace d'adressage avec le processus parent et ils n'avaient besoin que d'un contexte réduit commutateur, ce qui rendrait le changement de contexte plus efficace.
Dans un Linux contemporain (2.6.x), il n'y a pas beaucoup de différence de performances entre un changement de contexte d'un processus par rapport à un thread (seul le truc MMU est supplémentaire pour le thread). Il y a le problème avec l'espace d'adressage partagé, ce qui signifie qu'un pointeur défectueux dans un thread peut corrompre la mémoire du processus parent ou un autre thread dans le même espace d'adressage.
Un processus est protégé par la MMU, donc un pointeur défectueux provoquera juste un signal 11 et aucune corruption.
J'utiliserais généralement des processus (pas beaucoup de surcharge de changement de contexte sous Linux, mais une protection de la mémoire en raison de MMU), mais pthreads si j'avais besoin d'une classe de planificateur en temps réel, ce qui est une tasse de thé différente tous ensemble.
Pourquoi pensez-vous que les threads ont un gain de performances aussi important sous Linux? Avez-vous des données à ce sujet, ou est-ce juste un mythe?
la source
Dans quelle mesure vos tâches sont-elles étroitement liées?
S'ils peuvent vivre indépendamment les uns des autres, alors utilisez des processus. S'ils dépendent les uns des autres, utilisez des threads. De cette façon, vous pouvez tuer et redémarrer un mauvais processus sans interférer avec le fonctionnement des autres tâches.
la source
Pour compliquer encore les choses, il existe une chose telle que le stockage local par thread et la mémoire partagée Unix.
Le stockage local par thread permet à chaque thread d'avoir une instance distincte des objets globaux. La seule fois où je l'ai utilisé, c'était lors de la construction d'un environnement d'émulation sur linux / windows, pour du code d'application qui s'exécutait dans un RTOS. Dans le RTOS, chaque tâche était un processus avec son propre espace d'adressage, dans l'environnement d'émulation, chaque tâche était un thread (avec un espace d'adressage partagé). En utilisant TLS pour des choses comme les singletons, nous avons pu avoir une instance distincte pour chaque thread, tout comme dans le «vrai» environnement RTOS.
La mémoire partagée peut (évidemment) vous donner les avantages de performances d'avoir plusieurs processus accèdent à la même mémoire, mais au prix / risque d'avoir à synchroniser les processus correctement. Pour cela, un processus peut créer une structure de données dans la mémoire partagée, puis envoyer un descripteur à cette structure via une communication interprocessus traditionnelle (comme un canal nommé).
la source
Dans mes travaux récents avec LINUX, il y a une chose à savoir, c'est les bibliothèques. Si vous utilisez des threads, assurez-vous que toutes les bibliothèques que vous pouvez utiliser sur plusieurs threads sont thread-safe. Cela m'a brûlé plusieurs fois. En particulier, libxml2 n'est pas thread-safe prêt à l'emploi. Il peut être compilé avec thread-safe mais ce n'est pas ce que vous obtenez avec l'installation d'aptitude.
la source
Je dois être d'accord avec ce que vous avez entendu. Lorsque nous comparons notre cluster (
xhpl
et autres), nous obtenons toujours de bien meilleures performances avec les processus sur les threads.</anecdote>
la source
La décision entre thread / processus dépend un peu de l'utilisation que vous en ferez. L'un des avantages d'un processus est qu'il a un PID et peut être tué sans interrompre également le parent.
Pour un exemple réel de serveur Web, apache 1.3 ne supportait que plusieurs processus, mais en 2.0, ils ont ajouté une abstraction pour que vous puissiez basculer entre les deux. Commentaires semble à convenir que les processus sont plus robustes , mais les discussions peuvent donner un peu de meilleures performances (sauf pour les fenêtres où les performances des processus sucent et vous ne souhaitez que d'utiliser les threads).
la source
Dans la plupart des cas, je préférerais les processus aux threads. les threads peuvent être utiles lorsque vous avez une tâche relativement plus petite (surcharge de processus >> temps pris par chaque unité de travail divisée) et qu'il y a un besoin de partage de mémoire entre elles. Pensez à un large éventail. En outre (hors sujet), notez que si l'utilisation de votre processeur est à 100% ou proche de celle-ci, le multithreading ou le traitement ne retireront aucun avantage. (en fait ça va empirer)
la source
Threads -> Threads partage un espace mémoire, c'est une abstraction du CPU, il est léger. Processus -> Les processus ont leur propre espace mémoire, c'est une abstraction d'un ordinateur. Pour paralléliser la tâche, vous devez abstraire un processeur. Cependant, les avantages de l'utilisation d'un processus sur un thread sont la sécurité, la stabilité tandis qu'un thread utilise moins de mémoire que le processus et offre une latence moindre. Un exemple en termes de web serait chrome et firefox. Dans le cas de Chrome, chaque onglet est un nouveau processus, donc l'utilisation de la mémoire de Chrome est supérieure à celle de Firefox, tandis que la sécurité et la stabilité fournies sont meilleures que celles de Firefox. La sécurité ici fournie par Chrome est meilleure, car chaque onglet est un nouvel onglet de processus différent ne peut pas espionner dans l'espace mémoire d'un processus donné.
la source
Je pense que tout le monde a fait un excellent travail en répondant à votre question. J'ajoute simplement plus d'informations sur le thread par rapport au processus sous Linux pour clarifier et résumer certaines des réponses précédentes dans le contexte du noyau. Donc, ma réponse concerne le code spécifique au noyau sous Linux. Selon la documentation du noyau Linux, il n'y a pas de distinction claire entre thread et processus, sauf que le thread utilise un espace d'adressage virtuel partagé contrairement au processus. Notez également que le noyau Linux utilise le terme «tâche» pour faire référence au processus et au thread en général.
"Il n'y a pas de structures internes implémentant des processus ou des threads, mais une structure task_struct décrivant une unité de planification abstraite appelée tâche"
Toujours selon Linus Torvalds, vous ne devriez PAS du tout penser au processus par rapport au thread et parce que c'est trop limitatif et la seule différence est le COE ou le contexte d'exécution en termes de "séparation de l'espace d'adressage du parent" ou d'espace d'adressage partagé. En fait, il utilise un exemple de serveur Web pour faire valoir son point de vue ici (qui recommande fortement la lecture).
Crédit complet à la documentation du noyau Linux
la source
Si vous devez partager des ressources, vous devez vraiment utiliser des threads.
Considérez également le fait que les changements de contexte entre les threads sont beaucoup moins chers que les changements de contexte entre les processus.
Je ne vois aucune raison d'aller explicitement avec des processus séparés, sauf si vous avez une bonne raison de le faire (sécurité, tests de performances éprouvés, etc ...)
la source