web-dev-qa-db-fra.com

Gestionnaire de files d'attente de tâches multithread

Je dois gérer des tâches multitâches exigeant beaucoup de ressources processeur dans une application interactive. Comme arrière-plan, mon application spécifique est une interface de conception technique. Lorsqu'un utilisateur ajuste différents paramètres et options dans un modèle, plusieurs simulations sont exécutées en arrière-plan et les résultats s'affichent au fur et à mesure de leur achèvement, probablement même si l'utilisateur est en train de modifier des valeurs. Comme les simulations multiples prennent un temps variable (certaines millisecondes, certaines 5 secondes, d'autres 10 minutes), il s’agit essentiellement de faire en sorte que le retour d’affichage soit affiché le plus rapidement possible, mais les travaux qui ont déjà démarré ont été abandonnés mais ne sont plus nécessaires, des modifications de l'utilisateur les ont déjà invalidées. Différents changements d'utilisateur peuvent invalider différents calculs. Par conséquent, 10 simulations différentes peuvent être exécutées à tout moment. Certaines simulations ont plusieurs parties qui ont des dépendances (les simulations A et B peuvent être calculées séparément, mais j'ai besoin de leurs résultats pour générer la simulation C, je dois donc attendre que A et B aient fini en premier avant de commencer C).

Je suis assez confiant que la méthode au niveau du code pour gérer ce type d'application est une sorte de file d'attente de tâches multithread. Cela inclut les fonctionnalités de soumission de travaux pour exécution, de définition des priorités de tâche, d’attente de fin des travaux, de spécification de dépendances (effectuez ce travail, mais uniquement une fois le travail X et le travail Y terminés), d’annuler des sous-ensembles de travaux répondant à certains critères, de rechercher des informations. il reste des emplois, en définissant le nombre de threads et les priorités, etc. Et le support multiplateforme est également très utile.

Ce ne sont pas des idées ou des désirs nouveaux en matière de logiciels, mais je suis au début de la phase de conception de mon application et je dois choisir quelle bibliothèque utiliser pour gérer de telles tâches. J'ai déjà écrit mes propres gestionnaires de fils bruts en C (je pense que c'est un rite de passage), mais je souhaite utiliser des outils modernes sur lesquels baser mon travail, et non mes propres bidouilles.

La première pensée est de courir vers OpenMP mais je ne suis pas sûr que ce soit ce que je veux. OpenMP est idéal pour la parallélisation à un niveau précis, déroulant automatiquement les boucles et autres. Bien que multiplateforme, il envahit également votre code avec #pragmas. Mais la plupart du temps, il n’est pas conçu pour la gestion de tâches volumineuses. En particulier pour annuler des travaux en attente ou spécifier des dépendances. Possible, oui, mais ce n'est pas élégant.

J'ai remarqué que Google Chrome utilise un tel gestionnaire de tâches, même pour les tâches les plus triviales. L'objectif de conception semble être de garder le fil d'interaction utilisateur aussi léger et agile que possible, de sorte que tout ce qui peut être généré de manière asynchrone devrait l'être. En regardant la source Chrome, cela ne semble pas être une bibliothèque générique, mais il est toujours intéressant de voir comment la conception utilise des lancements asynchrones pour maintenir une interaction rapide. Cela commence à ressembler à ce que je fais.

Il y a encore d'autres options:

Surge.Act: une bibliothèque de type Boost pour définir les tâches. Il repose sur OpenMP, mais permet d'enchaîner des dépendances, ce qui est bien Nice. Il ne semble pas qu'il y ait un gestionnaire qui peut être interrogé, des emplois annulés, etc. C'est un projet obsolète, il est donc effrayant de s'en fier.

File d'attente est assez proche de ce que je pense, mais c'est un article de 5 ans, pas une bibliothèque prise en charge.

Boost.threads a une synchronisation indépendante de la plate-forme Nice, mais ce n'est pas un gestionnaire de tâches. POCO a des conceptions très propres pour le lancement de tâches, mais encore une fois pas un gestionnaire complet pour les tâches de chaînage. (Peut-être que je sous-estime POCO cependant).

Ainsi, bien qu'il existe des options disponibles, je ne suis pas satisfait et je ressens le besoin de lancer à nouveau ma propre bibliothèque. Mais je préférerais utiliser quelque chose qui existe déjà. Même après avoir cherché (ici sur SO et sur le net), je n'ai rien trouvé qui me convienne, bien que j'imagine que ce doit être un type d'outil souvent nécessaire. Il existe donc sûrement une bibliothèque communautaire ou au moins la conception commune. Sur SO, il y a eu quelques messages à propos de files d'attente de travaux , mais rien ne semble correspondre.

Mon post ici consiste à vous demander tous les outils existants que j'ai manqués et/ou comment vous avez créé votre propre file d'attente de tâches multithreads.

32
Marc Ditto

Nous avons dû créer notre propre système de file d’attente de travaux pour répondre à des exigences similaires aux vôtres (le fil de l’interface utilisateur doit toujours répondre dans un délai de 33 ms, les travaux peuvent durer de 15 à 15 000 ms), car rien ne répondait vraiment à nos besoins, encore moins était performant .

Malheureusement, notre code est à peu près aussi propriétaire que celui-ci, mais je peux vous donner certaines des caractéristiques les plus saillantes:

  • Nous démarrons un thread par cœur au début du programme. Chacun tire le travail d'une file d'attente globale. Les tâches consistent en un objet fonction et un glob de données associées (en réalité une élaboration sur un func_ptr et void *). Le fil 0, la boucle client rapide, n'est pas autorisé à travailler sur des travaux, mais le reste s'empare comme il le peut.
  • La file d'attente des tâches elle-même doit être une structure de données sans verrouillage, telle qu'une liste à accès unique sans verrouillage (Visual Studio en contient un ). Évitez d'utiliser un mutex; la contention pour la file d'attente est étonnamment élevée et la saisie de mutex est coûteuse.
  • Rassemblez toutes les données nécessaires au travail dans l'objet de travail lui-même - évitez de placer un pointeur du travail dans le tas principal, car vous devrez gérer les conflits entre les travaux et les verrous, entre autres choses lentes et ennuyeuses. Par exemple, tous les paramètres de simulation doivent aller dans le blob de données local du travail. La structure des résultats doit évidemment être quelque chose qui survit au travail: vous pouvez y remédier soit en: a) en accrochant les objets du travail même après la fin de leur exécution (vous pouvez donc utiliser leur contenu depuis le fil principal), ou b) attribuer une structure de résultats spécialement pour chaque travail et insérer un pointeur dans l'objet de données du travail. Même si les résultats eux-mêmes ne résulteront pas du travail, cela donne effectivement au travail un accès exclusif à sa mémoire de sortie, vous évitant ainsi d'avoir à vous servir de verrous.

  • En fait, je simplifie un peu au-dessus, car nous devons chorégraphier exactement quels travaux sont exécutés sur quels cœurs. Ainsi, chaque cœur dispose de sa propre file d’attente, mais c’est probablement inutile pour vous.

17
Crashworks

J'ai roulé le mien, basé sur Boost.threads. J'ai été assez surpris de voir à quel point l'écriture de si peu de code m'avait coûté. Si vous ne trouvez pas quelque chose de déjà fait, n'ayez pas peur de rouler le vôtre. Entre Boost.threads et votre expérience depuis que vous écrivez la vôtre, cela pourrait être plus facile que vous ne vous en souvenez.

Pour les options prédéfinies, n'oubliez pas que Chromium est sous licence très conviviale, vous pourrez donc éventuellement rouler votre propre bibliothèque générique autour de son code.

5
Ryan Graham

Microsoft travaille sur un ensemble de technologies pour la prochaine version de Visual Studio 2010, appelé runtime de simultanéité, bibliothèque de modèles parallèles et bibliothèque d'agents asynchrones, qui aidera probablement. Le Concuntime Runtime offrira une planification basée sur des règles, c'est-à-dire vous permettant de gérer et de composer plusieurs instances de planificateur (similaires aux pools de threads mais avec affinitisation et équilibrage de la charge entre les instances), Parallel Pattern Library proposera une programmation basée sur des tâches et des boucles parallèles avec un STL comme modèle de programmation. La bibliothèque Agents propose un modèle de programmation basé sur les acteurs et prend en charge la création de pipelines de flux de données simultanés, c'est-à-dire la gestion des dépendances décrites ci-dessus. Malheureusement, ce n'est pas encore sorti, vous pouvez donc en lire plus sur notre blog de l'équipe ou regarder certaines des vidéos sur channel9 il y a aussi un très grand CTP disponible au téléchargement ainsi que.

Si vous recherchez une solution aujourd'hui, les blocs de construction de threads d'Intel et la bibliothèque de threads de boost sont à la fois de bonnes bibliothèques et disponibles dès maintenant. JustSoftwareSolutions a publié une implémentation de std :: thread qui correspond au brouillon C++ 0x et, bien sûr, OpenMP est largement disponible si vous recherchez un parallélisme à base de boucles à granularité fine.

Le véritable défi auquel d'autres ont fait allusion consiste à identifier et à décomposer correctement le travail en tâches adaptées à une exécution simultanée (c'est-à-dire à ne pas partager un état partagé non protégé), à comprendre les dépendances qui existent entre elles et à minimiser les conflits qui peuvent survenir sur les goulots d'étranglement protection de l'état partagé ou en s'assurant que la boucle de répartition d'une file d'attente de travail est à faible conflit ou sans verrouillage) ... et cela sans planification des détails d'implémentation qui fuient dans le reste de votre code.

-Meule

4
Rick

Est-ce que quelque chose comme threadpool vous serait utile? Il est basé sur boost :: threads et implémente une simple file d'attente de tâches qui transfère les fonctions de travail aux threads regroupés.

3
greyfade

Vous voudrez peut-être examiner Programmation basée sur le flux - elle est basée sur des fragments de données diffusés en continu entre des composants asynchrones. Il existe des versions Java et C # du pilote, ainsi qu'un certain nombre de composants précodés. Il est intrinsèquement multithread - en fait, le seul code à un seul thread est contenu dans les composants, bien que vous puissiez ajouter des contraintes de temps aux règles de planification standard. Bien que le niveau de grain utilisé soit trop fin, vous pouvez utiliser certains éléments ici.

2
Paul Morrison

Vous voudrez peut-être regarder Les blocs de construction de threads Intel . Je crois que cela fait ce que vous voulez et avec la version 2, c'est Open Source.

1
Shane Powell

Il y a beaucoup de gestionnaires de ressources distribués sur le marché. Le logiciel qui répond à presque toutes vos exigences est Sun Grid Engine . SGE est utilisé sur certains des plus gros supercalculateurs du monde et est en cours de développement.

Il existe également des solutions similaires dans Couple , Plate-forme LSF et Condor .

Il semble que vous souhaitiez peut-être lancer le vôtre, mais les fonctionnalités ci-dessus sont nombreuses.

1
AdamK

Jetez un coup d'œil à boost :: future (mais voyez aussi ces discussion et proposition ) qui ressemble à une très bonne base de parallélisme (en particulier, il semble offrir un excellent support pour C- dépend de situations de type A et B).

J'ai un peu regardé OpenMP mais (comme vous) je n'étais pas convaincu que cela fonctionnerait bien pour tout sauf le code numérique Fortran/C. Les Threading Building Blocks d’Intel me paraissaient plus intéressants.

Si cela se produit, il n’est pas trop difficile de rouler votre propre au-dessus de boost :: thread. [Explication: un thread farm (la plupart des gens l’appelleraient un pool) tire son travail d’un queue de thread-safe (sans danger pour le thread) de fonctions (tâches ou travaux). Voir tests et benchmark pour des exemples d'utilisation. J'ai des complications supplémentaires à effectuer (éventuellement) sur des tâches de support avec priorités, et sur le cas où l'exécution de tâches peut générer plus de tâches dans la file d'attente (cela rend encore plus problématique de savoir quand tout le travail est terminé; les références à "en attente" sont ceux qui peuvent traiter le cas). Pourrait vous donner quelques idées quand même.]

1
timday

Je ne sais pas si vous recherchez une bibliothèque C++ (ce que je pense que vous êtes), mais le framework Fork/Join de Doug Lea pour Java 7 est très pratique et fait exactement ce que vous voulez. Vous seriez probablement capable de l'implémenter en C++ ou de trouver une bibliothèque pré-implémentée.

Plus d'infos ici: http://artisans-serverintellect-com.si-eioswww6.com/default.asp?W1

0
Itay

Peut-être un peu tard, mais regardez aussi ThreadWeaver: http://en.wikipedia.org/wiki/ThreadWeaver

0
user133281