Multithreading: quel est l'intérêt de plus de threads que de cœurs?


142

Je pensais que l'intérêt d'un ordinateur multicœur était qu'il pouvait exécuter plusieurs threads simultanément. Dans ce cas, si vous avez une machine quad-core, quel est l'intérêt d'avoir plus de 4 threads en cours d'exécution à la fois? Ne seraient-ils pas simplement en train de voler du temps (ressources CPU) les uns aux autres?


52
nous apprécions ce type de questions, ils remettent en question le très fondamental de quelque chose, qui est pris pour acquis .. continuez à venir ..
Srinivas Reddy Thatiparthy

6
À quand remonte la dernière fois que Firefox, MS Word, Winamp, Eclipse et un gestionnaire de téléchargement (plus de quatre programmes / processus) fonctionnaient simultanément sur votre machine quad core? En outre, une seule application peut parfois générer plus de quatre threads - qu'en est-il?
Amarghosh

1
Voler n'est pas nécessairement mauvais. Vous pouvez avoir un fil avec une priorité plus élevée pour les tâches importantes qui doivent voler du temps.
kichik

1
@Amarghosh J'imagine que c'était la question, pourquoi une seule application peut vouloir générer plus de threads que de cœurs si cela ne semble pas apporter d'avantages en termes de performances. Et votre exemple avec plus de quatre programmes n'est pas tout à fait pertinent ici. Comme vous l'avez bien noté, ce sont des processus. La fonction multitâche du système d'exploitation (multiplexage de processus) a très peu à voir avec les threads dans un processus.
Aleksandr Ivannikov

Réponses:


81

La réponse tourne autour de l'objectif des threads, qui est le parallélisme: exécuter plusieurs lignes d'exécution distinctes à la fois. Dans un système «idéal», vous auriez un thread s'exécutant par cœur: pas d'interruption. En réalité, ce n'est pas le cas. Même si vous avez quatre cœurs et quatre threads de travail, votre processus et ses threads seront constamment remplacés par d'autres processus et threads. Si vous exécutez un système d'exploitation moderne, chaque processus a au moins un thread, et beaucoup en ont plus. Tous ces processus s'exécutent en même temps. Vous avez probablement plusieurs centaines de threads en cours d'exécution sur votre machine en ce moment. Vous n'obtiendrez jamais une situation où un thread s'exécute sans que le temps ne lui soit `` volé ''. (Eh bien, vous pourriez si cela fonctionne en temps réel, si vous utilisez un système d'exploitation en temps réel ou, même sous Windows, utilisez une priorité de thread en temps réel. Mais c'est rare.)

Avec cela en arrière-plan, la réponse: Oui, plus de quatre threads sur une véritable machine à quatre cœurs peuvent vous donner une situation où ils `` volent du temps l'un à l'autre '', mais seulement si chaque thread individuel a besoin de 100% de CPU . Si un thread ne fonctionne pas à 100% (comme un thread d'interface utilisateur peut ne pas l'être, ou un thread effectuant une petite quantité de travail ou attendant quelque chose d'autre), un autre thread en cours de planification est en fait une bonne situation.

C'est en fait plus compliqué que ça:

  • Et si vous avez cinq morceaux de travail qui doivent tous être effectués en même temps? Il est plus logique de les exécuter tous en même temps que d'en exécuter quatre, puis d'exécuter le cinquième plus tard.

  • Il est rare qu'un thread ait réellement besoin de 100% de CPU. Au moment où il utilise des E / S disque ou réseau, par exemple, il peut passer du temps à attendre à ne rien faire d'utile. C'est une situation très courante.

  • Si vous avez du travail à exécuter, un mécanisme courant consiste à utiliser un pool de threads. Il peut sembler judicieux d'avoir le même nombre de threads que les cœurs, mais le pool de threads .Net a jusqu'à 250 threads disponibles par processeur . Je ne sais pas pourquoi ils font cela, mais je suppose que c'est à voir avec la taille des tâches qui sont données pour s'exécuter sur les threads.

Donc: voler du temps n'est pas une mauvaise chose (et ce n'est pas vraiment un vol non plus: c'est ainsi que le système est censé fonctionner.) Écrivez vos programmes multithread en fonction du type de travail que les threads feront, qui peut ne pas être du processeur -lié. Déterminez le nombre de threads dont vous avez besoin en fonction du profilage et de la mesure. Vous trouverez peut-être plus utile de penser en termes de tâches ou de travaux, plutôt que de threads: écrivez des objets de travail et donnez-les à un pool à exécuter. Enfin, à moins que votre programme ne soit vraiment critique pour les performances, ne vous inquiétez pas trop :)


17
+1 pour "mais seulement si chaque thread individuel a besoin de 100% de CPU". C'était l'hypothèse que je n'avais pas réalisé que je faisais.
Nick Heiner

1
Une merveilleuse réponse à une excellente question. Je vous remercie!
Edgecase le

53

Le fait qu'un thread existe ne signifie pas toujours qu'il est en cours d'exécution. De nombreuses applications de threads impliquent que certains threads se mettent en veille jusqu'à ce qu'il soit temps pour eux de faire quelque chose - par exemple, l'entrée utilisateur déclenche les threads pour se réveiller, effectuer un traitement et se rendormir.

Essentiellement, les threads sont des tâches individuelles qui peuvent fonctionner indépendamment les unes des autres, sans avoir besoin d'être conscient de la progression d'une autre tâche. Il est tout à fait possible d'en avoir plus que vous ne pouvez en exécuter simultanément; ils sont toujours utiles pour plus de commodité, même s'ils doivent parfois faire la queue les uns derrière les autres.


12
Bien dit. L'argument «un thread par CPU» s'applique uniquement au code lié au processeur. La programmation asynchrone est une autre raison d'utiliser des threads.
Joshua Davis

26

Le fait est que, même si vous n'obtenez aucune accélération réelle lorsque le nombre de threads dépasse le nombre de cœurs, vous pouvez utiliser des threads pour démêler des éléments de logique qui ne devraient pas avoir à être interdépendants.

Dans une application même modérément complexe, utiliser un seul thread, essayer de tout faire rapidement, fait hacher le «flux» de votre code. Le thread unique passe la plupart de son temps à interroger cela, à vérifier cela, à appeler des routines de manière conditionnelle si nécessaire, et il devient difficile de voir autre chose qu'un bourbier de minuties.

Comparez cela avec le cas où vous pouvez dédier des threads à des tâches afin que, en regardant n'importe quel thread individuel, vous puissiez voir ce que fait ce thread. Par exemple, un thread peut bloquer l'attente sur l'entrée d'une socket, analyser le flux en messages, filtrer les messages et, lorsqu'un message valide arrive, le transmettre à un autre thread de travail. Le thread de travail peut travailler sur des entrées provenant d'un certain nombre d'autres sources. Le code de chacun d'entre eux affichera un flux propre et ciblé, sans avoir à faire de vérifications explicites qu'il n'y a rien d'autre à faire.

Partitionner le travail de cette manière permet à votre application de s'appuyer sur le système d'exploitation pour planifier ce qu'il faut faire ensuite avec le processeur, vous n'avez donc pas à effectuer des vérifications conditionnelles explicites partout dans votre application sur ce qui pourrait bloquer et ce qui est prêt à traiter.


1
C'est une pensée intéressante ... J'ai toujours entendu dire que le multithreading d'une application est un ajout net de complexité, mais ce que vous dites a du sens.
Nick Heiner

Le multithreading d'une application ajoute de la complexité si ses préoccupations ne sont pas correctement séparées. S'il est conçu avec un chevauchement minimal de préoccupations (et donc un état partagé), il s'agit d'une économie nette dans les problèmes de complexité.
JUSTE MON AVIS correct

Il existe des moyens de structurer des applications à un seul thread afin que le flux de contrôle soit plus clair au niveau où vous écrivez des programmes. OTOH, si vous pouvez structurer vos fils de manière à ce qu'ils ne se transmettent que des messages (au lieu d'avoir des ressources partagées), il est assez simple de comprendre ce qui se passe et de tout faire fonctionner.
Donal Fellows

1
Il faut souligner, cependant, que l'utilisation de threads ne peut simplifier les choses que jusqu'à un certain point. Trop souvent, on essaie de faire faire à deux threads le travail qui devrait à juste titre être fait par un seul, auquel la complexité revient à la pelle. Les symptômes en sont des besoins excessifs de communication et de synchronisation afin de coordonner certains résultats souhaités.
JustJeff

15

Si un thread attend une ressource (comme charger une valeur de la RAM dans un registre, des E / S disque, un accès réseau, lancer un nouveau processus, interroger une base de données ou attendre l'entrée de l'utilisateur), le processeur peut travailler sur un thread différent et revenez au premier thread une fois que la ressource est disponible. Cela réduit le temps que le processeur passe inactif, car le processeur peut effectuer des millions d'opérations au lieu de rester inactif.

Considérez un thread qui a besoin de lire des données sur un disque dur. En 2014, un cœur de processeur typique fonctionne à 2,5 GHz et peut être capable d'exécuter 4 instructions par cycle. Avec un temps de cycle de 0,4 ns, le processeur peut exécuter 10 instructions par nanoseconde. Avec des temps de recherche mécaniques typiques du disque dur d'environ 10 millisecondes, le processeur est capable d'exécuter 100 millions d'instructions dans le temps nécessaire pour lire une valeur sur le disque dur. Il peut y avoir des améliorations significatives des performances avec les disques durs avec un petit cache (4 Mo de mémoire tampon) et les disques hybrides avec quelques Go de stockage, car la latence des données pour les lectures séquentielles ou les lectures à partir de la section hybride peut être plusieurs ordres de grandeur plus rapide.

Un cœur de processeur peut basculer entre les threads (le coût pour mettre en pause et reprendre un thread est d'environ 100 cycles d'horloge) tandis que le premier thread attend une entrée à latence élevée (quelque chose de plus cher que les registres (1 horloge) et la RAM (5 nanosecondes)). E / S disque, accès réseau (latence de 250 ms), lecture de données sur un CD ou un bus lent, ou appel à une base de données. Avoir plus de threads que de cœurs signifie qu'un travail utile peut être effectué pendant que les tâches à forte latence sont résolues.

Le processeur dispose d'un planificateur de threads qui attribue la priorité à chaque thread et permet à un thread de s'endormir, puis de reprendre après un temps prédéterminé. C'est le travail du programmateur de threads de réduire les battements, qui se produiraient si chaque thread n'exécutait que 100 instructions avant d'être à nouveau mis en veille. La surcharge des threads de commutation réduirait le débit utile total du cœur du processeur.

Pour cette raison, vous souhaiterez peut-être diviser votre problème en un nombre raisonnable de threads. Si vous écrivez du code pour effectuer une multiplication de matrice, la création d'un thread par cellule dans la matrice de sortie peut être excessive, alors qu'un thread par ligne ou par n lignes dans la matrice de sortie peut réduire les frais généraux de création, de mise en pause et de reprise des threads.

C'est aussi pourquoi la prédiction de branche est importante. Si vous avez une instruction if qui nécessite le chargement d'une valeur depuis la RAM mais que le corps des instructions if et else utilise des valeurs déjà chargées dans les registres, le processeur peut exécuter une ou les deux branches avant que la condition n'ait été évaluée. Une fois la condition revenue, le processeur appliquera le résultat de la branche correspondante et rejettera l'autre. Effectuer un travail potentiellement inutile ici est probablement mieux que de passer à un autre thread, ce qui pourrait conduire à des débordements.

Alors que nous sommes passés des processeurs monocœur à haute vitesse d'horloge aux processeurs multicœurs, la conception de la puce s'est concentrée sur le bourrage de plus de cœurs par matrice, l'amélioration du partage des ressources sur puce entre les cœurs, de meilleurs algorithmes de prédiction de branche, une meilleure surcharge de commutation de thread, et une meilleure planification des threads.


la même chose peut être faite avec un seul thread et une file d'attente: \ y a-t-il vraiment un avantage à avoir 80 threads sur 2-4 cœurs, plutôt que d'avoir simplement 2-4 cœurs qui mangent juste les tâches d'une file d'attente dès qu'elles arrivent et ils n'ont rien à faire?
Dmitry

8

La plupart des réponses ci-dessus parlent de performances et de fonctionnement simultané. Je vais aborder cela sous un angle différent.

Prenons le cas, disons, d'un programme d'émulation de terminal simpliste. Vous devez faire les choses suivantes:

  • surveillez les caractères entrants du système distant et affichez-les
  • surveillez les éléments provenant du clavier et envoyez-les au système distant

(Les vrais émulateurs de terminal font plus, y compris potentiellement l'écho des éléments que vous tapez sur l'écran, mais nous passerons là-dessus pour le moment.)

Maintenant, la boucle de lecture à partir de la télécommande est simple, selon le pseudocode suivant:

while get-character-from-remote:
    print-to-screen character

La boucle de surveillance du clavier et d'envoi est également simple:

while get-character-from-keyboard:
    send-to-remote character

Le problème, cependant, est que vous devez le faire simultanément. Le code doit maintenant ressembler davantage à ceci si vous n'avez pas de thread:

loop:
    check-for-remote-character
    if remote-character-is-ready:
        print-to-screen character
    check-for-keyboard-entry
    if keyboard-is-ready:
        send-to-remote character

La logique, même dans cet exemple délibérément simplifié qui ne prend pas en compte la complexité réelle des communications, est assez obscure. Avec le threading, cependant, même sur un seul noyau, les deux boucles de pseudo-code peuvent exister indépendamment sans entrelacer leur logique. Étant donné que les deux threads seront principalement liés aux E / S, ils ne mettent pas une charge lourde sur le processeur, même s'ils sont, à proprement parler, plus de gaspillage de ressources processeur que la boucle intégrée.

Maintenant, bien sûr, l'utilisation dans le monde réel est plus compliquée que ce qui précède. Mais la complexité de la boucle intégrée augmente de façon exponentielle à mesure que vous ajoutez plus de préoccupations à l'application. La logique est de plus en plus fragmentée et vous devez commencer à utiliser des techniques telles que les machines à états, les coroutines, etc. pour que les choses soient gérables. Gérable, mais non lisible. Le filetage garde le code plus lisible.

Alors pourquoi n'utiliseriez-vous pas le filetage?

Eh bien, si vos tâches sont liées au processeur au lieu des E / S, le threading ralentit en fait votre système. La performance en souffrira. Beaucoup, dans de nombreux cas. ("Thrashing" est un problème courant si vous supprimez trop de threads liés au processeur. Vous finissez par passer plus de temps à changer les threads actifs qu'à exécuter le contenu des threads eux-mêmes.) En outre, l'une des raisons pour lesquelles la logique ci-dessus est si simple est que j'ai choisi très délibérément un exemple simpliste (et irréaliste). Si vous vouliez faire écho à ce qui a été tapé à l'écran, vous avez un nouveau monde de blessures lorsque vous introduisez le verrouillage des ressources partagées. Avec une seule ressource partagée, ce n'est pas tellement un problème, mais cela commence à devenir un problème de plus en plus important car vous avez plus de ressources à partager.

Donc, en fin de compte, le filetage concerne beaucoup de choses. Par exemple, il s'agit de rendre les processus liés aux E / S plus réactifs (même s'ils sont globalement moins efficaces) comme certains l'ont déjà dit. Il s'agit également de rendre la logique plus facile à suivre (mais uniquement si vous minimisez l'état partagé). Il s'agit de beaucoup de choses et vous devez décider au cas par cas si ses avantages l'emportent sur ses inconvénients.


6

Bien que vous puissiez certainement utiliser des threads pour accélérer les calculs en fonction de votre matériel, l'une de leurs principales utilisations est de faire plus d'une chose à la fois pour des raisons de convivialité.

Par exemple, si vous devez effectuer un traitement en arrière-plan tout en restant réactif aux entrées de l'interface utilisateur, vous pouvez utiliser des threads. Sans threads, l'interface utilisateur se bloquait à chaque fois que vous tentiez d'effectuer un traitement intensif.

Voir aussi cette question connexe: Utilisations pratiques des threads


La gestion de l'interface utilisateur est un exemple classique de tâche liée aux E / S. Il n'est pas bon d'avoir un seul cœur de processeur effectuant à la fois les tâches de traitement et d'E / S.
Donal Fellows

6

Je ne suis pas du tout d'accord avec l'affirmation de @ kyoryu selon laquelle le nombre idéal est un thread par CPU.

Pensez-y de cette façon: pourquoi avons-nous des systèmes d'exploitation multi-traitements? Pour la plupart de l'histoire de l'ordinateur, presque tous les ordinateurs avaient un processeur. Pourtant, à partir des années 1960, tous les «vrais» ordinateurs avaient des systèmes d'exploitation multi-traitements (ou multi-tâches).

Vous exécutez plusieurs programmes afin que l'un puisse s'exécuter tandis que d'autres sont bloqués pour des choses comme IO.

mettons de côté les arguments sur la question de savoir si les versions de Windows avant NT étaient multi-tâches. Depuis lors, tous les vrais OS avaient le multitâche. Certains ne l'exposent pas aux utilisateurs, mais c'est quand même là, faire des choses comme écouter la radio du téléphone portable, parler à la puce GPS, accepter l'entrée de la souris, etc.

Les threads ne sont que des tâches un peu plus efficaces. Il n'y a pas de différence fondamentale entre une tâche, un processus et un thread.

Un processeur est une chose terrible à gaspiller, alors ayez beaucoup de choses prêtes à l'utiliser quand vous le pouvez.

Je conviendrai qu'avec la plupart des langages procéduraux, C, C ++, Java, etc., écrire un code thread-safe approprié demande beaucoup de travail. Avec 6 processeurs cœurs sur le marché aujourd'hui et 16 processeurs cœurs non loin de là, je m'attends à ce que les gens s'éloignent de ces anciens langages, car le multi-threading est de plus en plus une exigence critique.

Le désaccord avec @kyoryu est juste à mon humble avis, le reste est un fait.


5
Si vous avez beaucoup de threads liés au processeur , alors le nombre idéal est un par CPU (ou peut-être un de moins, pour en laisser un pour gérer toutes les E / S et le système d'exploitation et tout le reste). Si vous avez des threads liés aux E / S , vous pouvez en empiler beaucoup sur un seul processeur. Différentes applications ont différents mélanges de tâches liées au processeur et liées aux E / S; c'est tout à fait naturel, mais pourquoi il faut faire attention aux déclarations universelles.
Donal Fellows

1
Bien sûr, la différence la plus importante entre les threads et les processus est que sous Windows, il n'y a pas de fork (), donc la création de processus est très coûteuse, ce qui conduit à une surutilisation des threads.
ninjalj

À l'exception du repliement des protéines, du SETI, etc., il n'y a pas de tâches utilisateur pratiques qui sont liées au calcul pendant très longtemps. Il est toujours nécessaire d'obtenir des informations de l'utilisateur, de parler au disque, de parler au SGBD, etc. Oui, le coût de fork () est l'une des nombreuses choses que Cutler maudit NT avec ce que les autres à DEC savaient.
fishtoprecords

5

Imaginez un serveur Web qui doit répondre à un nombre arbitraire de requêtes. Vous devez traiter les demandes en parallèle, car sinon chaque nouvelle demande doit attendre que toutes les autres demandes soient terminées (y compris l'envoi de la réponse sur Internet). Dans ce cas, la plupart des serveurs Web ont beaucoup moins de cœurs que le nombre de requêtes qu'ils traitent habituellement.

Cela facilite également la tâche du développeur du serveur: vous n'avez qu'à écrire un programme de thread qui sert une requête, vous n'avez pas à penser à stocker plusieurs requêtes, à l'ordre dans lequel vous les servez, etc.


2
Vous écrivez un logiciel pour un système d'exploitation qui prend en charge le threading mais n'a pas de capacité pour le multiplexage io? Je pense que le serveur Web est probablement un mauvais exemple car dans ce cas, le multiplexage io sera presque toujours plus efficace que la création de plus de threads que de cœurs.
Jason Coco

3

De nombreux threads seront endormis, attendant l'entrée de l'utilisateur, les E / S et d'autres événements.


Pour sûr. utilisez simplement le Gestionnaire de tâches sur Windows ou TOP sur un système d'exploitation réel, et voyez combien de tâches / processus sont en attente. C'est toujours 90% ou plus.
fishtoprecords

2

Les threads peuvent améliorer la réactivité des applications d'interface utilisateur. De plus, vous pouvez utiliser des threads pour optimiser le travail de vos cœurs. Par exemple, sur un seul cœur, vous pouvez avoir un thread effectuant les E / S et un autre effectuant des calculs. S'il s'agissait d'un seul thread, le cœur pourrait essentiellement être inactif en attendant la fin de l'E / S. C'est un exemple assez élevé, mais les threads peuvent certainement être utilisés pour marteler votre processeur un peu plus fort.


Plus précisément, un thread peut être en attente d'E / S tandis qu'un autre effectue le calcul. Si les E / S prenaient des cycles CPU (importants), il n'y aurait aucun avantage à l'exécuter dans un thread séparé. L'avantage est que votre thread de calcul peut fonctionner pendant que votre thread d'E / S tourne ses pouces en attendant qu'un gros cylindre en aluminium se mette en place, ou que des paquets arrivent sur le fil d'Islande, ou autre.
Ken

2

Un processeur, ou CPU, est la puce physique qui est connectée au système. Un processeur peut avoir plusieurs cœurs (un cœur est la partie de la puce qui est capable d'exécuter des instructions). Un cœur peut apparaître pour le système d'exploitation comme plusieurs processeurs virtuels s'il est capable d'exécuter simultanément plusieurs threads (un thread est une seule séquence d'instructions).

Un processus est un autre nom pour une application. En général, les processus sont indépendants les uns des autres. Si un processus meurt, cela n'entraîne pas la mort d'un autre processus. Il est possible pour les processus de communiquer ou de partager des ressources telles que la mémoire ou les E / S.

Chaque processus dispose d'un espace d'adressage et d'une pile séparés. Un processus peut contenir plusieurs threads, chacun capable d'exécuter des instructions simultanément. Tous les threads d'un processus partagent le même espace d'adressage, mais chaque thread aura sa propre pile.

Espérons que ces définitions et d'autres recherches utilisant ces principes fondamentaux vous aideront à comprendre.


2
Je ne vois pas du tout comment cela répond à sa question. Mon interprétation de sa question porte sur l'utilisation des threads des cœurs et l'utilisation optimale des ressources disponibles, ou sur le comportement des threads lorsque vous augmentez leur nombre, ou quelque chose du genre de toute façon.
David

@David ce n'était peut-être pas une réponse directe à ma question, mais j'ai toujours l'impression d'avoir appris en la lisant.
Nick Heiner

1

L'utilisation idéale des threads est, en effet, un par cœur.

Cependant, à moins que vous n'utilisiez exclusivement des E / S asynchrones / non bloquantes, il y a de fortes chances que vous ayez des threads bloqués sur E / S à un moment donné, ce qui n'utilisera pas votre CPU.

En outre, les langages de programmation typiques rendent quelque peu difficile l'utilisation d'un thread par CPU. Les langages conçus autour de la concurrence (comme Erlang) peuvent faciliter l'utilisation de threads supplémentaires.


L'utilisation de threads pour des tâches périodiques est un flux de travail très courant et bienvenu, et ce serait beaucoup moins qu'idéal s'ils volaient un noyau.
Nick Bastin

@Nick Bastin: Oui, mais il est plus efficace de coller ces tâches dans une file d'attente de tâches et de les exécuter à partir de cette file d'attente (ou d'une stratégie similaire). Pour une efficacité optimale, 1 thread par cœur bat tout, car il évite la surcharge due au changement de contexte inutile et à l'allocation de piles supplémentaires. Quoi qu'il en soit, la tâche périodique doit voler un cœur lorsqu'elle est «active», car le processeur ne peut effectuer qu'une seule tâche par cœur (plus des choses comme l'hyperthreading si disponible).
kyoryu

@Nick Bastin: Malheureusement, comme je l'ai dit dans la réponse principale, la plupart des langages modernes ne se prêtent pas bien à l'implémentation facile d'un système qui le fait efficacement n'est pas anodin - vous finissez par lutter contre l'usage typique de la langue.
kyoryu

Mon point n'est pas qu'un thread par core n'est pas optimal, c'est qu'un thread par core est un rêve de pipe (sauf si vous êtes intégré) et concevoir pour essayer de le frapper est une perte de temps, donc vous pourriez aussi bien faites ce qui vous facilite la tâche (et n'est de toute façon pas moins efficace sur un planificateur moderne), plutôt que d'essayer d'optimiser le nombre de threads que vous utilisez. Devrions-nous lancer des threads sans raison valable? Bien sûr que non, mais la question de savoir si vous gaspillez inutilement des ressources informatiques est un problème quel que soit le threading.
Nick Bastin

@Nick Bastin: Donc, pour résumer, un thread par cœur est idéal, mais y parvenir n'est pas très probable. J'aurais probablement dû être plus fort que «quelque peu difficile» en parlant de la probabilité de réaliser une telle chose.
kyoryu le

1

De la façon dont certaines API sont conçues, vous n'avez pas d'autre choix que de les exécuter dans un thread séparé (tout ce qui a des opérations de blocage). Un exemple serait les bibliothèques HTTP de Python (AFAIK).

Habituellement, ce n'est pas vraiment un problème (si c'est un problème, le système d'exploitation ou l'API doit être livré avec un mode de fonctionnement asynchrone alternatif, c'est-à-dire:) select(2), car cela signifie probablement que le thread va dormir pendant l'attente d'I / O achèvement. D'un autre côté, si quelque chose fait un calcul lourd, vous devez le mettre dans un thread séparé que, par exemple, le thread GUI (à moins que vous n'appréciez le multiplexage manuel).


1

Je sais que c'est une question très ancienne avec beaucoup de bonnes réponses, mais je suis ici pour souligner quelque chose qui est important dans l'environnement actuel:

Si vous souhaitez concevoir une application pour le multi-threading, vous ne devez pas concevoir pour un paramètre matériel spécifique. La technologie des processeurs progresse assez rapidement depuis des années et le nombre de cœurs augmente régulièrement. Si vous concevez délibérément votre application de telle sorte qu'elle n'utilise que 4 threads, vous vous restreignez potentiellement dans un système octa-core (par exemple). Maintenant, même les systèmes à 20 cœurs sont disponibles dans le commerce, donc une telle conception fait certainement plus de mal que de bien.


0

En réponse à votre première conjecture: les machines multicœurs peuvent exécuter simultanément plusieurs processus, pas seulement les multiples threads d'un même processus.

En réponse à votre première question: le but de plusieurs threads est généralement d'effectuer simultanément plusieurs tâches dans une seule application. Les exemples classiques sur le net sont un programme de messagerie envoyant et recevant du courrier, et un serveur Web recevant et envoyant des requêtes de page. (Notez qu'il est essentiellement impossible de réduire un système comme Windows à n'exécuter qu'un seul thread ou même un seul processus. Exécutez le Gestionnaire des tâches de Windows et vous verrez généralement une longue liste de processus actifs, dont beaucoup exécuteront plusieurs threads. )

En réponse à votre deuxième question: la plupart des processus / threads ne sont pas liés au processeur (c'est-à-dire qu'ils ne fonctionnent pas de manière continue et ininterrompue), mais s'arrêtent et attendent fréquemment la fin des E / S. Pendant cette attente, d'autres processus / threads peuvent s'exécuter sans «voler» le code en attente (même sur une machine à un seul cœur).


-5

Un thread est une abstraction qui vous permet d'écrire du code aussi simple qu'une séquence d'opérations, ignorant parfaitement que le code est exécuté entrelacé avec un autre code, ou parqué en attente d'E / S, ou (peut-être un peu plus conscient) en attendant d'autres threads événements ou messages.


J'aurais peut-être modifié cela en ajoutant plus d'exemples depuis les votes négatifs - mais un thread (ou un processus, dans ce contexte presque aucune différence) n'a été inventé pour augmenter les performances, mais plutôt pour simplifier le code asynchrone et éviter d'écrire des machines à états compliquées qui devait gérer tous les super-états possibles dans le programme. En fait, il y avait généralement un processeur même dans les grands serveurs. Je suis juste curieux de savoir pourquoi ma réponse est considérée comme anti-utile?
KarlP

-8

Le fait est que la grande majorité des programmeurs ne comprennent pas comment concevoir une machine à états. Être capable de tout mettre dans son propre thread libère le programmeur d'avoir à réfléchir à la façon de représenter efficacement l'état des différents calculs en cours afin qu'ils puissent être interrompus et repris plus tard.

À titre d'exemple, considérons la compression vidéo, une tâche très gourmande en processeur. Si vous utilisez un outil d'interface graphique, vous souhaitez probablement que l'interface reste réactive (afficher la progression, répondre aux demandes d'annulation, redimensionner la fenêtre, etc.). Ainsi, vous concevez votre logiciel d'encodeur pour traiter une grande unité (une ou plusieurs images) à la fois et l'exécuter dans son propre thread, séparé de l'interface utilisateur.

Bien sûr, une fois que vous vous êtes rendu compte qu'il aurait été bien de pouvoir enregistrer l'état d'encodage en cours afin de pouvoir fermer le programme pour redémarrer ou jouer à un jeu gourmand en ressources, vous réalisez que vous auriez dû apprendre à concevoir des machines à états à partir du début. Soit cela, soit vous décidez de créer un tout nouveau problème d'hibernation des processus de votre système d'exploitation afin que vous puissiez suspendre et reprendre des applications individuelles sur le disque ...


7
Cela ne vaut pas (tout à fait!) Un -1, mais sérieusement, c'est à peu près la chose la plus stupidement sarcastique que j'aie entendu dire à ce sujet. Je n'ai, par exemple, aucun problème pour mettre en œuvre une machine à états. Pas du tout. Je n'aime tout simplement pas les utiliser quand il existe d'autres outils qui laissent un code plus clair et plus facile à maintenir . Les machines d'État ont leur place, et dans ces endroits, elles ne peuvent pas être égalées. L'entrelacement des opérations gourmandes en ressources processeur avec les mises à jour de l'interface graphique n'est pas l'un de ces endroits. À tout le moins, les coroutines sont un meilleur choix là-bas, le filetage étant encore meilleur.
JUSTE MON AVIS correct

À tous ceux qui modifient ma réponse, ce n'est PAS un argument contre l'utilisation des threads! Si vous pouvez coder une machine à états, c'est génial, et bien sûr, il est souvent logique d'exécuter des machines à états dans des threads séparés, même si vous n'êtes pas obligé de le faire. Mon commentaire était que souvent le choix d'utiliser des threads est fait principalement par le désir d'éviter de concevoir des machines à états, que de nombreux programmeurs considèrent comme "trop ​​difficiles", plutôt que pour tout autre avantage.
R .. GitHub STOP HELPING ICE
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.