web-dev-qa-db-fra.com

Multithreading vs multiprocessing

Je suis nouveau dans ce genre de programmation et j'ai besoin de votre point de vue.

Je dois créer une application mais je n'arrive pas à la faire calculer assez rapidement. J'ai déjà essayé Intel TBB, et il est facile à utiliser, mais je n'ai jamais utilisé d'autres bibliothèques.

En programmation multiprocesseur, je lis sur OpenMP et Boost pour le multithreading, mais je ne connais pas leurs avantages et inconvénients.

En C++, quand la programmation multi-thread est-elle avantageuse par rapport à la programmation multiprocesseur et vice versa? Laquelle est la mieux adaptée aux calculs lourds ou au lancement de nombreuses tâches ...? Quels sont leurs avantages et inconvénients lorsque nous créons une application conçue avec eux? Et enfin, avec quelle bibliothèque est-il préférable de travailler?

30
Nazka

Le multithreading signifie exactement cela, en exécutant plusieurs threads. Cela peut être fait sur un système monoprocesseur ou sur un système multiprocesseur.

Sur un système à processeur unique, lors de l'exécution de plusieurs threads, l'observation réelle de l'ordinateur faisant plusieurs choses en même temps (c.-à-d. Multitâche) est une illusion, car ce qui se passe réellement sous le capot, c'est qu'il existe un programmateur logiciel effectuer un découpage temporel sur le processeur unique. Ainsi, une seule tâche se produit à un moment donné, mais le planificateur bascule entre les tâches assez rapidement pour que vous ne remarquiez jamais qu'il existe plusieurs processus, threads, etc., se disputant la même ressource CPU.

Sur un système multiprocesseur, le besoin de découpage temporel est réduit. L'effet de découpage temporel est toujours là, car un système d'exploitation moderne pourrait avoir des centaines de threads rivalisant pour deux processeurs ou plus, et il n'y a généralement jamais de relation 1-à-1 entre le nombre de threads et le nombre de cœurs de traitement disponibles. Donc, à un moment donné, un thread devra s'arrêter et un autre thread démarrera sur un processeur que les deux threads partagent. Ceci est à nouveau géré par le planificateur du système d'exploitation. Cela étant dit, avec un système multiprocesseurs, vous pouvez avoir deux choses en même temps, contrairement au système monoprocesseur.

En fin de compte, les deux paradigmes sont vraiment quelque peu orthogonaux dans le sens où vous aurez besoin du multithreading chaque fois que vous souhaitez que deux tâches ou plus s'exécutent de manière asynchrone, mais en raison du découpage temporel, vous n'avez pas nécessairement besoin d'un système multiprocesseur pour accomplir cette. Si vous essayez d'exécuter plusieurs threads et effectuez une tâche hautement parallèle (c'est-à-dire, essayez de résoudre une intégrale), alors oui, plus vous pouvez jeter de cœurs à un problème, mieux c'est. Vous n'aurez pas nécessairement besoin d'une relation 1 à 1 entre les threads et les cœurs de traitement, mais en même temps, vous ne voulez pas créer autant de threads que vous vous retrouvez avec des tonnes de threads inactifs car ils doivent attendre être planifié sur l'un des cœurs CPU disponibles. D'un autre côté, si vos tâches parallèles nécessitent un composant séquentiel, c'est-à-dire qu'un thread attendra le résultat d'un autre thread avant de pouvoir continuer, vous pourrez peut-être exécuter plus de threads avec un certain type de barrière ou de méthode de synchronisation afin que les threads qui doivent être inactifs ne tournent pas loin en utilisant le temps CPU, et seuls les threads qui doivent s'exécuter se disputent les ressources CPU.

54
Jason

Il y a quelques points importants qui, je pense, devraient être ajoutés à l'excellente réponse de @Jason.

Premièrement, le multithreading n'est pas toujours une illusion même sur un seul processeur - il y a des opérations qui n'impliquent pas le processeur. Il s'agit principalement d'E/S - disque, réseau, terminal, etc. La forme de base pour une telle opération est blocage ou synchrone, c.-à-d. que votre programme attend que l'opération soit terminée puis continue. En attendant, le CPU est basculé vers un autre processus/thread.

si vous avez quelque chose à faire pendant cette période (par exemple, calcul en arrière-plan en attendant la saisie de l'utilisateur, servir une autre demande, etc.), vous avez essentiellement deux options:

  • utilisez des E/S asynchrones : vous appelez un non bloquant E/S en lui fournissant un fonction de rappel, en lui disant "appelez cette fonction lorsque vous avez terminé". L'appel revient immédiatement et l'opération d'E/S se poursuit en arrière-plan. Vous continuez avec les autres trucs.

  • utilisez le multithreading : vous avez un thread dédié pour chaque type de tâche. Pendant que l'un attend l'appel d'E/S bloquant, l'autre continue.

Les deux approches sont des paradigmes de programmation difficiles, chacune a ses avantages et ses inconvénients.

  • avec les E/S asynchrones, la logique de la logique du programme est moins évidente et est difficile à suivre et à déboguer. Cependant, vous évitez les problèmes de thread-safety.
  • avec les threads, le défi est d'écrire thread-safe programmes. Les failles de sécurité des threads sont des bugs désagréables qui sont assez difficiles à reproduire. Une utilisation excessive du verrouillage peut en fait conduire à une dégradation au lieu d'améliorer les performances.

(venir au multi-traitement)

Le multithreading est devenu populaire sous Windows car la manipulation des processus est assez lourde sur Windows (création d'un processus, changement de contexte, etc.) par opposition aux threads qui sont beaucoup plus légers (du moins c'était le cas lorsque je travaillais sur Win2K).

Sous Linux/Unix, les processus sont beaucoup plus légers. De plus, les threads (AFAIK) sous Linux sont implémentés en fait comme une sorte de processus en interne, il n'y a donc aucun gain dans le changement de contexte des threads par rapport aux processus. Cependant, vous devez utiliser une certaine forme de IPC (communications inter-processus), comme mémoire partagée, canaux, file d'attente de messages, etc.

Sur une note plus lite, regardez le FAQ SQLite , qui déclare "Les threads sont mauvais"! :)

21
davka

Pour répondre à la première question: La meilleure approche consiste à simplement utiliser des techniques de multithreading dans votre code jusqu'à ce que vous n'obteniez pas suffisamment d'avantages. Supposons que le système d'exploitation gère la délégation à plusieurs processeurs s'ils sont disponibles.

Si vous travaillez réellement sur un problème où le multithreading ne suffit pas, même avec plusieurs processeurs (ou si vous utilisez un système d'exploitation qui n'utilise pas ses multiples processeurs), alors vous pouvez vous soucier de découvrir comment obtenir plus de puissance . Ce qui pourrait signifier la génération de processus à travers un réseau vers d'autres machines.

Je n'ai pas utilisé TBB, mais j'ai utilisé IPP et je l'ai trouvé efficace et bien conçu. Boost est portable.

4
Mike C

Je voulais juste mentionner que le paradigme de programmation basée sur les flux ( http://www.jpaulmorrison.com/fbp ) est une approche naturellement multiprogrammation/multitraitement du développement d'applications. Il fournit une vue d'application cohérente de haut niveau à bas niveau. Les implémentations Java et C # tirent parti de tous les processeurs de votre machine, mais l'ancienne implémentation C++ n'utilise qu'un seul processeur. Cependant, elle pourrait assez facilement être étendue pour utiliser BOOST (ou pthreads, I supposons) par l'utilisation du verrouillage sur les connexions. J'avais commencé à le convertir pour utiliser des fibres, mais je ne sais pas s'il est utile de continuer sur cette voie. :-) Les commentaires seraient appréciés. BTW Les implémentations Java et C # peuvent même communiquer entre elles à l'aide de sockets.

0
Paul Morrison