2010-01-11 4 views
2

Je viens de commencer à programmer avec des threads POSIX sur un système Linux dual-core x86_64. Il semble que 256 threads est l'optimum pour les performances avec la façon dont je l'ai fait. Je me demande comment cela pourrait être? Et si cela peut signifier que mon approche est mauvaise et qu'une meilleure approche nécessiterait beaucoup moins de threads et serait tout aussi rapide ou plus rapide?Si 256 threads donnent de meilleures performances que 8 j'ai probablement eu la mauvaise approche?

Pour des informations plus (le programme en question est un squelette pour un générateur d'image réglée M-multi-thread) voir les questions suivantes, je l'ai déjà demandé:

Using threads, how should I deal with something which ideally should happen in sequential order?

How can my threaded image generating app get it’s data to the gui?

Je devrais peut-être mentionner que le squelette (dans lequel j'ai reproduit des fonctionnalités minimales pour les tests et la comparaison) affiche maintenant l'image, et les calculs réels sont effectués presque deux fois plus vite que le programme non-threaded. Par conséquent, si 256 threads s'exécutant plus vite que 8 threads n'indiquent pas une mauvaise approche de l'enfilage, pourquoi 256 threads surpassent-ils 8 threads?

Le cas de test de vitesse est une partie de la Mandelbrot Set situé à:

xmin -0.76243636067708333333333328 
xmax -0.7624335575810185185185186 
ymax 0.077996663411458333333333929 

calculé à un maximum de 30000 itérations.

Sur le non-threaded version le temps de rendu sur mon système est d'environ 15 secondes. Sur la version filetée, la vitesse moyenne pour 8 threads est de 7,8 secondes, alors que 256 threads est de 7,6 secondes.

+0

Comment fonctionne 2 threads? –

+0

2 fils sont plus lents encore. La différence entre 8 et 256 threads est d'environ 150 ms, avec un temps global de 7,7 secondes - ce qui n'est pas un gros problème, mais si ça grossit avec des images beaucoup plus grandes, ce serait sympa :) –

Répondre

4

Eh bien, probablement oui, vous faites quelque chose de mal. Cependant, dans certaines circonstances, 256 threads fonctionneraient mieux que 8 sans que vous ayez nécessairement un mauvais modèle de thread. Il faut se rappeler que le fait d'avoir 8 threads ne signifie pas que tous les 8 threads fonctionnent réellement tout le temps. Chaque fois qu'un thread effectue un appel système bloquant sur le système d'exploitation, le thread cesse de fonctionner et attend le résultat. En attendant, un autre fil peut souvent faire du travail. Il y a ce mythe que l'on ne peut utilement utiliser plus de threads que de contextes sur le CPU, mais ce n'est pas vrai. Si vos threads bloquent un appel système, il peut être essentiel d'avoir un autre thread disponible pour faire plus de travail. (En pratique, lorsque le bloc de threads a tendance à être moins laborieux, ce n'est pas toujours le cas.)

Tout dépend de la charge de travail et il n'y a pas de nombre correct de threads pour une application particulière.Généralement, vous ne voulez jamais moins de threads disponibles que le système d'exploitation s'exécutera, et c'est la seule vraie règle. (Malheureusement, cela peut être très difficile à trouver et les gens ont tendance à déclencher autant de threads que de contextes, puis utiliser des syscalls non bloquants si possible.)

2

Pourrait-il être votre application est io lié? Comment les données d'image sont-elles générées?

+0

Je ne sais pas s'il est lié. Comment pourrais-je détecter cela? –

+0

Si la source de votre imagedata est lue depuis votre disque dur, votre réseau ou une autre source, vos threads attendront en parallèle pour lire à partir de cette source. Si les données utilisées pour générer l'image sont calculées à 100%, ou préalablement lues dans la mémoire, il y a de fortes chances qu'elle soit liée à l'UC. – Evert

+0

Les ensembles Mandelbrot sont entièrement calculés. – caf

1

Une amélioration des performances obtenue en allouant plus de threads que de cœurs suggère que le CPU n'est pas le goulot d'étranglement. Si un accès d'E/S tel qu'un disque, une mémoire ou même un accès réseau est impliqué, vos résultats sont parfaitement sensés.

1

Vous bénéficiez probablement de Simultaneous Multithreading (SMT). Votre système d'exploitation planifie plus de threads que les cœurs disponibles, et permutera les threads qui ne sont pas bloqués en attente de ressources (comme un chargement de mémoire). Cela peut très efficacement cacher les latences de votre système de mémoire de votre programme et est la technique utilisée pour un grand effet de parallélisation massive dans CUDA pour la programmation GPU généraliste.

+0

Le multithreading simultané est identique à l'hyperthreading utilisé dans les nouveaux processeurs Intel. L'OP a déclaré qu'il utilisait un système dual-core, et à ma connaissance, il n'existe pas de CPU Intel dual-core hyperthreading moderne. –

+0

Aussi, en ce qui concerne CUDA, il est possible que vous pensiez à Single Instruction Multiple Threads (SIMT), qui a un acronyme similaire. Je n'ai pas entendu parler de GPU utilisant SMT. –

1

Si vous voyez une augmentation de performance avec le saut à 256 threads, alors ce que vous avez probablement affaire est un goulot d'étranglement des ressources. À un moment donné, votre code attend un périphérique lent (un disque dur ou une connexion réseau, par exemple) afin de continuer. Avec plusieurs threads, attendre sur ce périphérique lent n'est pas un problème car au lieu de rester inactif et de tourner ses pouces électroniques, le processeur peut traiter un autre thread pendant que le premier thread attend sur le périphérique lent. Plus le nombre de threads parallèles est élevé, plus le processeur peut faire de travail pendant qu'il attend quelque chose d'autre.

Si vous constatez que les performances s'améliorent jusqu'à 256 threads, je suis tenté de dire que vous avez un goulot d'étranglement majeur dans les performances et ce n'est pas le CPU. Pour tester cela, essayez de voir si vous pouvez mesurer le temps d'inactivité des threads individuels. Je suspecte que vous verrez vos fils sont bloqués dans un état "bloqué" ou "en attente" pendant une plus longue partie de leur vie qu'ils passent dans l'état "courant" ou "actif". Certains débogueurs ou outils de profilage de fonction vous permettront de le faire, et je pense qu'il existe aussi des outils Linux pour le faire en ligne de commande.

Questions connexes