Nombre optimal de threads par noyau

281

Disons que j'ai un processeur à 4 cœurs et que je veux exécuter un processus dans le minimum de temps. Le processus est idéalement parallélisable, donc je peux en exécuter des morceaux sur un nombre infini de threads et chaque thread prend le même temps.

Étant donné que j'ai 4 cœurs, je ne m'attends à aucune accélération en exécutant plus de threads que de cœurs, car un seul cœur n'est capable d'exécuter qu'un seul thread à un moment donné. Je ne connais pas grand-chose au matériel, ce n'est donc qu'une supposition.

Existe-t-il un avantage à exécuter un processus parallélisable sur plus de threads que de cœurs? En d'autres termes, mon processus se terminera-t-il plus rapidement, plus lentement ou dans le même laps de temps si je l'exécute en utilisant 4000 threads plutôt que 4 threads?

Juliette
la source

Réponses:

254

Si vos threads ne font pas d'E / S, de synchronisation, etc., et qu'il n'y a rien d'autre en cours d'exécution, 1 thread par cœur vous donnera les meilleures performances. Cependant, ce n'est probablement pas le cas. L'ajout de plusieurs threads aide généralement, mais après un certain point, ils entraînent une certaine dégradation des performances.

Il n'y a pas longtemps, je faisais des tests de performances sur une machine à 2 cœurs exécutant une application ASP.NET sur Mono sous une charge assez décente. Nous avons joué avec le nombre minimum et maximum de threads et à la fin, nous avons découvert que pour cette application particulière dans cette configuration particulière, le meilleur débit se situait entre 36 et 40 threads. Tout ce qui se situait en dehors de ces limites était pire. Leçon apprise? Si j'étais vous, je testerais avec un nombre différent de threads jusqu'à ce que vous trouviez le bon numéro pour votre application.

Une chose est sûre: les threads 4k prendront plus de temps. Cela fait beaucoup de changements de contexte.

Gonzalo
la source
21
Je pense que la réponse de Gonzalo est bonne. J'ajouterais simplement que vous devriez expérimenter et mesurer. Votre programme sera différent du sien, du mien ou de quiconque et seules les mesures du comportement de votre propre programme répondront correctement à vos questions. La performance des programmes parallèles (ou simultanés) n'est pas un domaine où de bonnes conclusions peuvent être tirées des seuls premiers principes.
High Performance Mark
5
+1, + réponse: cela m'étonne que le fait d'avoir beaucoup plus de threads que de cœurs entraîne de meilleures performances, bien que cela ait du sens si plus de threads signifie une part de temps plus importante par rapport aux threads concurrents. Ce serait bien que mon application puisse détecter des différences de performances et se régler automatiquement sur le nombre optimal de threads.
Juliet
12
Cela ne devrait pas vous surprendre dans un scénario réel. Les threads bloquent l'attente des ressources IO comme l'accès au disque, le réseau, etc. Et attendent également que les ressources non IO comme les autres threads finissent d'utiliser des variables partagées. Ce que vous voulez vraiment atteindre, c'est le nombre minimum de threads de sorte qu'au moins un thread par cœur puisse toujours être en cours d'exécution.
patros
4
1 fil par âme n'est pas optimal. Il doit être légèrement plus, de préférence deux fois plus, car cela permettra à un autre thread de s'exécuter si un thread est temporairement bloqué. Même si ce n'est que sur la mémoire. C'est plus important si vous avez des systèmes (P4, I7, Sun Rock, etc.) qui comportent SMT / HT)
Marco van de Voort
1
D'où le "Ce n'est probablement pas le cas" dans ma réponse. Trouver le bon numéro dépend de l'application et de l'architecture sur laquelle elle s'exécute.
Gonzalo
129

Je suis d'accord avec la réponse de @ Gonzalo. J'ai un processus qui ne fait pas d'E / S, et voici ce que j'ai trouvé:

entrez la description de l'image ici

Notez que tous les threads fonctionnent sur un tableau mais sur des plages différentes (deux threads n'accèdent pas au même index), donc les résultats peuvent différer s'ils ont travaillé sur des tableaux différents.

La machine 1.86 est un MacBook Air avec un SSD. L'autre mac est un iMac avec un disque dur normal (je pense que c'est 7200 rpm). La machine Windows a également un disque dur à 7200 tr / min.

Dans ce test, le nombre optimal était égal au nombre de cœurs dans la machine.

Motasim
la source
14
+1 pour le graphique. Clairement, 1 thread par cœur est le meilleur, mais il est intéressant de noter que le système à quatre cœurs ne semble pas avoir un nombre de threads plus élevé (<100 de toute façon) comme les autres.
Jim Garrison du
46
-1 pour le graphique! Courbes lisses à travers des coordonnées x à valeur entière? Un saut sauvage de 1 2 3 à 10 20 30 à 50 100? Et les coordonnées y qui sont des multiples de 10 plus 2 pour faire bonne mesure. C'est ce que fait Excel, n'est-ce pas?
Spacedman
5
@Spacedman Oui, c'est ça. Les courbes lisses ont un aspect beaucoup plus agréable à mon humble avis. : D
Motasim
22
@PascalvKooten, Le problème n'est pas qu'il soit joli, c'est trompeur à première vue. Tout d'abord, l'axe y commence à 42, exagérant la différence apparente entre les machines testées. Deuxièmement, la progression étrange des valeurs de l'axe des x suggère que le «temps pris» ne s'ajuste pas linéairement avec le «nombre de threads», ceci est particulièrement vrai pour la ligne bleue. Je pense que le problème que les autres (y compris moi-même) avons, c'est qu'il dénature les données.
pauluss86
13
@Spacedman La critique sur le graphique est la chose la plus ridicule que j'ai rencontrée au cours des dernières 24 heures. Le graphique aide. Beaucoup. Période. Aurait-il pu être mieux fait? Personne ne s'y intéresse. Courbe lisse au lieu de discrète? C'est ton problème ???? Je suppose que vous n'inclueriez jamais un tel graphique dans leur réponse parce que vous n'avez pas le temps / l'énergie supplémentaire pour le rendre beau. C'est mon point.
Tyrex
50

Je sais que cette question est assez ancienne, mais les choses ont évolué depuis 2009.

Il y a deux choses à prendre en compte maintenant: le nombre de cœurs et le nombre de threads qui peuvent s'exécuter dans chaque cœur.

Avec les processeurs Intel, le nombre de threads est défini par l'hyperthreading qui n'est que de 2 (lorsqu'il est disponible). Mais Hyperthreading réduit votre temps d'exécution de deux, même si vous n'utilisez pas 2 threads! (c'est-à-dire 1 pipeline partagé entre deux processus - c'est bien quand vous avez plus de processus, pas si bien sinon. Plus de cœurs sont définitivement meilleurs!)

Sur d'autres processeurs, vous pouvez avoir 2, 4 ou même 8 threads. Donc, si vous avez 8 cœurs, chacun prenant en charge 8 threads, vous pouvez avoir 64 processus exécutés en parallèle sans changement de contexte.

"Pas de changement de contexte" n'est évidemment pas vrai si vous utilisez un système d'exploitation standard qui fera un changement de contexte pour toutes sortes d'autres choses hors de votre contrôle. Mais c'est l'idée principale. Certains systèmes d'exploitation vous permettent d'allouer des processeurs afin que seule votre application ait accès / utilisation dudit processeur!

D'après ma propre expérience, si vous avez beaucoup d'E / S, plusieurs threads sont bons. Si vous avez un travail intensif en mémoire (lecture source 1, lecture source 2, calcul rapide, écriture), avoir plus de threads n'aide pas. Encore une fois, cela dépend de la quantité de données que vous lisez / écrivez simultanément (c'est-à-dire si vous utilisez SSE 4.2 et lisez des valeurs de 256 bits, cela arrête tous les threads dans leur étape ... en d'autres termes, 1 thread est probablement beaucoup plus facile à implémenter et probablement presque aussi rapide, sinon plus rapide. Cela dépendra de votre architecture de processus et de mémoire, certains serveurs avancés gèrent des plages de mémoire distinctes pour des cœurs séparés, donc les threads séparés seront plus rapides en supposant que vos données sont correctement classées ... c'est pourquoi, sur certains architectures, 4 processus s'exécuteront plus rapidement que 1 processus avec 4 threads.)

Alexis Wilke
la source
4
Il y en a probablement d'autres, mais celui que je connais est le processeur POWER d'IBM. Ils avaient des systèmes avec 4 ou 8 threads par processeurs. Maintenant, ils peuvent lancer plus de cœurs, ils proposent donc 2 threads par cœur ...
Alexis Wilke
C'est ancien, mais la plupart des processeurs Intel i5, i7 ont des processeurs multi-threads comme par exemple les processeurs i7 ont généralement 4 cœurs, mais 8 threads.
Edgar.A
4
Les processeurs n'ont pas de threads. Ils ont des cœurs physiques et logiques. Avec l'hyperthreading, un seul cœur physique fonctionne comme deux cœurs logiques. J'avais une technologie qui insistait sur le fait que les processeurs ayant des threads était une chose réelle, alors j'ai dessiné une image sur le tableau blanc d'un processeur avec une broche de thread qui en sortait.
@TechnikEmpire Jetez un oeil à ce intel.com/content/www/us/en/processors/core/… , peut-être alors vous pouvez contacter Intel et dessiner eux aussi des fils.
g7k
24

Les performances réelles dépendront du rendement volontaire de chaque thread. Par exemple, si les threads n'effectuent AUCUNE E / S et n'utilisent aucun service système (c'est-à-dire qu'ils sont liés à 100% au processeur), alors 1 thread par cœur est optimal. Si les threads font quelque chose qui nécessite une attente, vous devrez expérimenter pour déterminer le nombre optimal de threads. 4000 threads entraîneraient une surcharge de planification importante, ce qui n'est probablement pas optimal non plus.

Jim Garrison
la source
21

La réponse dépend de la complexité des algorithmes utilisés dans le programme. J'ai trouvé une méthode pour calculer le nombre optimal de threads en effectuant deux mesures des temps de traitement Tn et Tm pour deux nombres arbitraires de threads "n" et "m". Pour les algorithmes linéaires, le nombre optimal de threads sera N = sqrt ((m n (Tm * (n-1) - Tn * (m-1))) / (n Tn-m Tm)).

Veuillez lire mon article concernant les calculs du nombre optimal pour différents algorithmes: pavelkazenin.wordpress.com

pkazen
la source
4
Pourquoi est-il déclassé? Je suis désolé mais c'est la meilleure réponse à cette question. gonzalo aborde la partie audacieuse de la question, et pkazen aborde le titre. Les deux réponses sont très utiles, mais la réponse pkazen est pertinente car nous avons une méthode systématique pour approximer le nombre de threads. Il donne même la formule des algorithmes linéaires.
tobiak777
1
Je n'ai pas downvote, mais si je le faisais, ce serait sur la base qu'il n'y a pas de véritable explication quant à pourquoi ou comment le nombre optimal de threads pourrait être lié à la complexité de l'algorithme, sauf en lisant l'intégralité de l'article lié, qui est une longue lecture (en raison de la complexité de l'article). Au-delà de cela, certains aspects de l'article ne sont pas clairs pour moi, surtout comment les résultats expérimentaux confirment la théorie.
Codebling
De plus, je crois que ce calcul suppose que vous avez un nombre infini de cœurs de processeur. Bien qu'il s'agisse certainement d'informations précieuses, la question se réfère à de vraies machines avec un petit nombre de cœurs.
Navneeth
9

J'ai pensé ajouter une autre perspective ici. La réponse dépend du fait que la question suppose une mise à l'échelle faible ou une mise à l'échelle forte.

De Wikipédia :

Faible mise à l'échelle: comment le temps de solution varie avec le nombre de processeurs pour une taille de problème fixe par processeur.

Mise à l'échelle forte: comment le temps de solution varie avec le nombre de processeurs pour une taille de problème totale fixe.

Si la question suppose une mise à l'échelle faible, la réponse de @ Gonzalo suffit. Cependant, si la question suppose une mise à l'échelle forte, il y a quelque chose de plus à ajouter. Dans une mise à l'échelle forte, vous supposez une taille de charge de travail fixe, donc si vous augmentez le nombre de threads, la taille des données sur lesquelles chaque thread doit travailler diminue. Sur les processeurs modernes, les accès à la mémoire sont coûteux et il serait préférable de conserver la localité en conservant les données dans des caches. Par conséquent, le nombre optimal probable de threads peut être trouvé lorsque l'ensemble de données de chaque thread tient dans le cache de chaque cœur (je n'entre pas dans les détails pour savoir s'il s'agit de cache (s) L1 / L2 / L3 du système).

Cela est vrai même lorsque le nombre de threads dépasse le nombre de cœurs. Par exemple, supposons qu'il existe 8 unités arbitraires (ou AU) de travail dans le programme qui seront exécutées sur une machine à 4 cœurs.

Cas 1: exécutez avec quatre threads où chaque thread doit terminer 2AU. Chaque thread prend 10 secondes pour terminer ( avec beaucoup de ratés de cache ). Avec quatre cœurs, le temps total sera de 10 s (10 s * 4 threads / 4 cœurs).

Cas 2: exécutez avec huit threads où chaque thread doit terminer 1AU. Chaque thread ne prend que 2s (au lieu de 5s en raison de la quantité réduite de cache cache ). Avec quatre cœurs, le temps total sera de 4 s (2 s * 8 threads / 4 cœurs).

J'ai simplifié le problème et ignoré les frais généraux mentionnés dans d'autres réponses (par exemple, les changements de contexte), mais j'espère que vous comprendrez qu'il pourrait être avantageux d'avoir plus de nombre de threads que le nombre de cœurs disponibles, selon la taille des données que vous '' re traitant.

manger
la source
7

4000 threads à la fois est assez élevé.

La réponse est oui et non. Si vous faites beaucoup de blocage des E / S dans chaque thread, alors oui, vous pouvez montrer des accélérations importantes faisant probablement jusqu'à 3 ou 4 threads par cœur logique.

Si vous ne faites pas beaucoup de blocages cependant, le surcoût supplémentaire avec le filetage le rendra plus lent. Utilisez donc un profileur et voyez où se trouvent les goulots d'étranglement dans chaque pièce éventuellement parallèle. Si vous effectuez des calculs lourds, alors plus d'un thread par CPU ne vous aidera pas. Si vous faites beaucoup de transfert de mémoire, cela n'aidera pas non plus. Si vous faites beaucoup d'E / S, comme pour l'accès au disque ou l'accès à Internet, alors oui, plusieurs threads aideront dans une certaine mesure, ou au moins rendront l'application plus réactive.

Earlz
la source
7

Référence.

Je commencerais à augmenter le nombre de threads pour une application, à partir de 1, puis j'allais à quelque chose comme 100, j'exécutais trois à cinq essais pour chaque nombre de threads et je construisais vous-même un graphique de la vitesse de fonctionnement par rapport au nombre de threads. .

Vous devriez que le boîtier à quatre threads soit optimal, avec de légères augmentations de l'exécution après cela, mais peut-être pas. Il se peut que votre application soit limitée en bande passante, c'est-à-dire que l'ensemble de données que vous chargez en mémoire est énorme, vous obtenez beaucoup de ratés de cache, etc., de sorte que 2 threads sont optimaux.

Vous ne pouvez pas savoir jusqu'à ce que vous testiez.

mmr
la source
3

Vous trouverez combien de threads vous pouvez exécuter sur votre machine en exécutant la commande htop ou ps qui renvoie le nombre de processus sur votre machine.

Vous pouvez utiliser la page de manuel sur la commande 'ps'.

man ps

Si vous souhaitez calculer le nombre de processus de tous les utilisateurs, vous pouvez utiliser l'une de ces commandes:

  1. ps -aux| wc -l
  2. ps -eLf | wc -l

Calcul du nombre d'un processus utilisateur:

  1. ps --User root | wc -l

Vous pouvez également utiliser "htop" [Référence] :

Installation sur Ubuntu ou Debian:

sudo apt-get install htop

Installation sur Redhat ou CentOS:

yum install htop
dnf install htop      [On Fedora 22+ releases]

Si vous souhaitez compiler htop à partir du code source, vous le trouverez ici .

Saeed Zahedian Abroodi
la source
2

L'idéal est 1 fil par noyau, tant qu'aucun des fils ne se bloque.

Un cas où cela peut ne pas être vrai: il existe d'autres threads en cours d'exécution sur le noyau, auquel cas plus de threads peuvent donner à votre programme une plus grande tranche du temps d'exécution.

patros
la source
Cela dépend si vous souhaitez que les processus d'arrière-plan des utilisateurs s'exécutent comme de la merde pendant que votre application est en cours d'exécution. Pour cette question, vous pouvez simplement définir une priorité en temps réel pour chaque thread et obtenir la puissance maximale. Mais les utilisateurs aiment le multitâche.
Earlz
2
Eh bien, nous avons affaire à une application magique idéalement parallélisable. Si jamais je créais une telle chose, je me sentirais autorisé à monopoliser le processeur autant que je le souhaite.
patros
2

Un exemple de nombreux threads ("pool de threads") vs un par cœur est celui de l'implémentation d'un serveur Web sous Linux ou Windows.

Étant donné que les sockets sont interrogés sous Linux, de nombreux threads peuvent augmenter la probabilité que l'un d'eux interroge le bon socket au bon moment - mais le coût de traitement global sera très élevé.

Sous Windows, le serveur sera implémenté à l'aide de ports d'achèvement d'E / S - IOCP - qui rendront l'événement d'application piloté: si une E / S se termine, le système d'exploitation lance un thread de secours pour le traiter. Une fois le traitement terminé (généralement avec une autre opération d'E / S comme dans une paire requête-réponse), le thread retourne au port IOCP (file d'attente) pour attendre la fin suivante.

Si aucune E / S n'est terminée, aucun traitement n'est à effectuer et aucun thread n'est lancé.

En effet, Microsoft ne recommande pas plus d'un thread par cœur dans les implémentations IOCP. Toute E / S peut être attachée au mécanisme IOCP. Les CIO peuvent également être affichés par l'application, si nécessaire.

Olof Forshell
la source
Je ne sais pas de quel Linux vous parlez, mais mes blocs jusqu'à ce qu'une connexion arrive. Je vous suggère de lire quelques éléments sur select () et FD_SET () et les fonctions / macros similaires.
Alexis Wilke
Ok, donc il n'y a pas de forme asynchrone qui revient immédiatement?
Olof Forshell
À partir de la page de manuel select ():timeout is an upper bound on the amount of time elapsed before select() returns. If both fields of the timeval structure are zero, then select() returns immediately. (This is useful for polling.) If timeout is NULL (no timeout), select() can block indefinitely.
Alexis Wilke
0

parlant du point de vue du calcul et de la mémoire (calcul scientifique), 4000 threads rendront l'application très lente. Une partie du problème est un surcoût très élevé de changement de contexte et très probablement une très mauvaise mémoire.

Mais cela dépend aussi de votre architecture. D'où j'ai entendu que les processeurs Niagara sont censés être capables de gérer plusieurs threads sur un seul cœur en utilisant une sorte de technique de pipelining avancée. Cependant, je n'ai aucune expérience avec ces processeurs.

Anycorn
la source
0

J'espère que cela a du sens, vérifiez l'utilisation du processeur et de la mémoire et mettez une valeur de seuil. Si la valeur seuil est franchie, ne permettez pas de créer un nouveau thread sinon autorisez ...

M. Gopal
la source