Ma société exécute actuellement un programme de simulation tiers (modélisation de risque de catastrophe naturelle) qui aspire des gigaoctets de données sur un disque, puis des craquements pendant plusieurs jours pour produire des résultats. Je serai bientôt invité à réécrire cela comme une application multi-threadé afin qu'elle fonctionne en heures au lieu de jours. Je m'attends à avoir environ 6 mois pour compléter la conversion et travaillera en solo. P>
Nous avons une boîte 24-PROC pour exécuter cela. J'aurai accès à la source du programme d'origine (écrit en C ++, je pense), mais à ce stade, je sais que très peu de choses sur la manière dont il est conçu. P>
J'ai besoin de conseils sur la façon de s'attaquer à cela. Je suis un programmeur expérimenté (~ 30 ans, travaillant actuellement en C # 3.5) mais n'a pas d'expérience multi-processeurs / multi-filetés. Je suis disposé et désireux d'apprendre une nouvelle langue si nécessaire. Je recherche des recommandations sur les langues, les ressources d'apprentissage, les livres, les directives architecturales. c. p>
Exigences: Windows OS. Un compilateur de qualité commerciale avec beaucoup de soutien et de bonnes ressources d'apprentissage disponibles. Il n'y a pas besoin d'une interface graphique fantaisie - elle fonctionnera probablement à partir d'un fichier de configuration et de mettre des résultats dans une base de données SQL Server. P>
EDIT: L'application actuelle est C ++ mais je n'utiliserai presque pas cette langue pour la réécriture. J'ai supprimé la balise C ++ que quelqu'un a ajouté. P>
16 Réponses :
Si vous pouvez diviser la charge de travail en morceaux de travail non dépendants (c'est-à-dire que le jeu de données peut être traité dans des bits, il n'y a pas beaucoup de dépendances de données), alors j'utiliserais un mécanisme de piscine / tâche de fil . Vraisemblablement quoi que ce soit C # a équivalent à Java.Util.ConCurrent de Java. Je créerais des unités de travail à partir des données et enveloppez-les dans une tâche, puis jetez les tâches dans la piscine de thread. P>
Bien sûr, la performance pourrait être une nécessité ici. Si vous pouvez conserver le noyau de code de traitement d'origine, vous pouvez l'appeler à partir de votre application C #. P>
Si le code comporte de nombreuses dépendances de données, il peut être beaucoup plus difficile de se briser dans des tâches filetées, mais vous pourrez peut-être rompre dans un pipeline d'actions. Cela signifie que le thread 1 passe des données au fil 2, qui transmet des données aux filets 3 à 8, qui passent des données sur le filetage 9, etc. P>
Si le code a beaucoup de mathématiques à virgule flottante, il peut être intéressant de regarder la réécriture dans Opencl ou Cuda et l'exécuter sur GPU au lieu des processeurs. P>
+1: J'étais sur le point d'écrire quelque chose dans ces lignes après avoir réaffecté la question.
S'il est possible de disposer de tous les threads de travailler sur des ensembles disjoints de données de processus et que d'autres informations stockées dans la base de données SQL vous permettent de le faire facilement en C ++ et de se détacher de nouveaux threads pour travailler sur leurs propres parties. en utilisant l'API Windows. Le serveur SQL traitera toute la magie de synchronisation dure avec ses transactions DB! Et bien sûr C ++ effectuera beaucoup plus vite que c #. P>
Vous devez définitivement réviser C ++ pour cette tâche et comprendre le code C ++ et rechercher des bogues d'efficacité dans le code existant ainsi que l'ajout de la fonctionnalité multi-threadée. P>
Je ne déteste pas assez cela pour la descendre, mais recommander une base de données SQL pour tout ce qui concerne les performances élevées? -0,5 au moins.
Une chose que nous avons faite dans cette situation qui a vraiment bien fonctionné pour nous, c'est de briser le travail à faire dans des morceaux individuels et des actions sur chaque morceau dans différents processeurs. Ensuite, nous avons des chaînes de transformateurs et de morceaux de données peuvent travailler à travers les chaînes de manière indépendante. Chaque ensemble de processeurs dans la chaîne peut s'exécuter sur plusieurs threads chacun et peut traiter plus ou moins de données en fonction de leurs propres performances par rapport aux autres processeurs de la chaîne. P>
Briser également les données et les actions en pièces plus petites rend l'application beaucoup plus maintenue et testable. P>
Votre plus gros problème dans un projet multithread est que trop d'état est visible à travers les threads - il est trop facile d'écrire du code qui lit / mutuelle les données de manière dangereuse, en particulier dans un environnement multiprocesseur où des problèmes tels que la cohérence de la cache, faiblement Mémoire cohérente etc. pourrait entrer en jeu. p>
Les conditions de race de débogage sont distinctement désagréables. P>
Approchez votre conception comme vous le feriez si, dites, vous envisagiez de distribuer votre travail sur plusieurs machines sur un réseau: c'est-à-dire d'identifier les tâches pouvant se passer en parallèle, quelles sont les sorties de chaque tâche. Les tâches sont et quelles tâches doivent compléter avant qu'une tâche donnée puisse commencer. Le point de l'exercice consiste à garantir que chaque place où les données deviennent visibles vers un autre fil, et chaque endroit où un nouveau fil est généré, sont soigneusement considérées. P>
Une fois que une telle conception initiale est terminée, il y aura une division claire de la propriété des données et des points clairs au cours de laquelle la propriété est prise / transférée; Et vous serez donc dans une très bonne position pour tirer parti des possibilités que Multithreading vous offre - des données partagées à moindre coût, une synchronisation bon marché, des structures de données partagées sans verrouillage - en toute sécurité. P>
Comme Tony Hoare a déclaré: "Ne communiquez pas en partageant, partageant en communiquant." Outre quelques files d'attente, il convient d'être possible qu'un seul thread agit sur un morceau de données à un moment donné. Essayez de rechercher l'approche du langage de programmation Go via des «canaux» qui applique cette pratique (mais n'utilisez pas Go, c'est pour jouer uniquement).
Il y a beaucoup de bits spécifiques de conseils individuels pouvant être donnés ici et plusieurs personnes l'ont déjà fait.
Cependant, personne ne peut vous dire exactement comment faire tout ce travail pour vos besoins spécifiques (que vous ne connaissez même pas bien vous-même), alors je vous recommande vivement de lire sur
Lisez sur Erlang et le "modèle Acteur" en particulier. Si vous prenez toutes vos données immuables, vous aurez beaucoup plus facile la parallèle à la parallèle. P>
Pourquoi pas? Vous pouvez toujours imiter certaines des astuces qui rendent Erlang bien adapté à cette
Et bien sûr, il a dit dans la question qu'il s'intéressait aux conseils sur le choix de la langue. Si définitivement +1 de moi
Erlang n'utilise pas de multithreading pour la performance qu'elle l'utilise pour faciliter la modélisation de flux de données du programme. Ce sera un mauvais choix pour son problème qui recherche une vitesse seulement
La plupart des autres réponses offrent de bons conseils en matière de partitionnement du projet - recherchez des tâches pouvant être protégées en parallèle avec très peu de partage de données requises. Soyez conscient des constructions sûres non-files telles que des variables statiques ou globales, ou des bibliothèques qui ne traitent pas de sécurité. Le pire que nous avons rencontré est le bibliothèque TNT , qui ne permet même même pas de fil-coffre-fort lit dans certaines circonstances. P>
Comme avec toute optimisation, concentrez-vous d'abord sur les goulots d'étranglement, car le filetage ajoute beaucoup de complexité que vous souhaitez éviter où il n'est pas nécessaire. P>
Vous aurez besoin d'une bonne compréhension des différents primitives de filetage (mutiles, sémaphores, sections critiques, conditions, etc.) et les situations dans lesquelles elles sont utiles. P>
Une chose que j'ajouterais, si vous avez l'intention de rester avec C ++, c'est que nous avons eu beaucoup de succès en utilisant le Boost bibliothèque .Thread. Il fournit la plupart des primitives multi-threading requises, bien que manquent de piscine de fil (et je me méfierais de la piscine non officielle «Boost», on peut localiser via Google, car elle souffre d'un certain nombre de problèmes d'impasse). p>
Vous avez étiqueté cette question comme C ++, mais vous avez mentionné que vous êtes un développeur C # actuellement, alors je ne sais pas si vous abordez cette affectation de C ++ ou C #. Quoi qu'il en soit, au cas où vous allez utiliser C # ou .NET (y compris C ++ / CLI): j'ai l'article MSDN suivant le signet et recommanderait vivement la lecture dans celle-ci dans le cadre de votre travail de préparation. P>
Il y a beaucoup de techniques qui peuvent être utilisées pour traiter de multithreading si vous concevez le projet pour cela. P>
Le plus général et universel est simplement "éviter l'état partagé". Dans la mesure du possible, copiez des ressources entre les threads, plutôt que de les rendre accéder à la même copie partagée. P>
Si vous écrivez vous-même le code de synchronisation de bas niveau vous-même, vous devez vous rappeler de ne rien faire absolument aucune hypothèse. Le compilateur et la CPU peuvent réorganiser votre code, créer des conditions de race ou des blocages où aucun ne semblerait possible lors de la lecture du code. Le seul moyen d'empêcher cela est avec des barrières de mémoire. Et rappelez-vous que même l'opération la plus simple peut être soumise à des problèmes de filetage. Quelque chose d'aussi simple que Si j'étais vous, j'irais avec un modèle de synchronisation de niveau supérieur que des serrures simples / mutiles / moniteurs / sections critiques si possible. Il y a quelques Bibliothèques CSP Disponible pour la plupart des langues et des plates-formes, y compris les langues et natives C ++. . p>
Cela rend généralement les conditions de course et les blocages triviaux pour détecter et fixer et permettent un niveau d'évolutivité ridicule. Mais il y a une certaine quantité de surcharge associée à ce paradigme également, chaque fil peut avoir moins de travail que ce serait avec d'autres techniques. Il exige également que toute la demande soit structurée spécifiquement pour ce paradigme (il est donc délicat de rénovation sur le code existant, mais comme vous commencez à partir de zéro, c'est moins un problème - mais cela ne vous sera toujours pas familier) < / p>
Une autre approche pourrait être Mémoire transactionnelle . Il est plus facile de s'intégrer à une structure de programme traditionnelle, mais de certaines limitations, et je ne connais pas de nombreuses bibliothèques de qualité de la production (STM.NET a récemment été publiée et peut être vérifiée. Intel a une C ++ compilateur avec des extensions STM intégrées dans la langue aussi bien) p>
Mais quelle que soit l'approche que vous utilisez, vous devrez réfléchir avec précaution sur la manière de fragmenter les travaux en tâches indépendantes et comment éviter les discussions croisées entre les threads. Chaque fois que deux threads accèdent à la même variable, vous avez un bogue potentiel. Et à tout moment deux threads accèdent la même variable OH, et si em> vous écrivez l'application en C ++, ne sous-estimez pas la langue. Vous devrez apprendre la langue en détail avant que vous puissiez écrire un code robuste, beaucoup moins robuste fileté em> code. P> ++ i code> n'est généralement pas atomique, et si plusieurs threads Access
i code>, vous obtiendrez des résultats imprévisibles.
Et bien sûr, simplement parce que vous avez attribué une valeur à une variable, cela ne garantit pas que la nouvelle valeur sera visible pour les autres threads. Le compilateur peut différer en réalité la rédaction de la mémoire. Encore une fois, une barrière de mémoire oblige à "affleurer" toutes les heures de mémoire en attente d'E / S. P>
Quelle que soit la technologie que vous allez écrire ceci, jetez un coup d'œil à un look A Cela doit lire un livre sur la concurrence "Programmation simultanée en Java" et pour .net, je recommande fortement le Retlang Library pour une application simultanée. P>
J'envisagerais de le faire dans .NET 4.0, car il a beaucoup de nouveau soutien spécifiquement ciblé pour rendre la rédaction de code simultané de l'écriture. Sa date de sortie officielle est le 22 mars 2010, mais elle aura probablement plus de temps à ce moment-là et vous pouvez commencer par la bêta 2 raisonnablement stable maintenant. P>
Vous pouvez soit utiliser c # que vous connaissez plus ou que vous pouvez utiliser géré C ++. P>
À un niveau élevé, essayez de briser le programme dans SYSTEM.THEADING.TASKS.TASKS est des unités de travail individuelles. En outre, je minimiserais l'utilisation de l'état partagé et envisager d'utiliser Parallèle.for (ou foreach ) et / ou PLINQ A > Si possible. P>
Si vous faites cela, beaucoup de lourdes levées seront faites pour vous de manière très efficace. C'est la direction que Microsoft va de plus en plus soutenir. P>
2 : je considérerais Faire cela dans .NET 4.0 car il a beaucoup de nouveau soutien spécifiquement ciblé pour rendre la rédaction de code simultané de l'écriture. Sa date de sortie officielle est le 22 mars 2010, mais elle aura probablement plus de temps à ce moment-là et vous pouvez commencer par la bêta 2 raisonnablement stable maintenant. À un niveau élevé, essayez de briser le programme dans System.threading.tasks.task est des unités de travail individuelles. De plus, je minimiserais l'utilisation de l'état partagé et envisagerais d'utiliser parallèle.Pour et / ou plinq dans la mesure du possible. Si vous faites cela, beaucoup de levage lourd sera fait pour vous de manière très efficace. 1 : http://msdn.microsoft.com/en-us/library/dd321424% 28VS.100% 29.aspx P>
Malgré le grand succès de la plate-forme .NET ne vous recommande pas d'utiliser cette nouvelle version, car les risques que cette décision peut soulever de sa stabilité.
Pour un projet de 6 mois, je dirais que cela paie certainement pour commencer à lire un bon livre sur le sujet en premier. Je suggérerais Programmation simultanée de Joe Duffy sur Windows . C'est le livre le plus complet que je connaisse sur le sujet et cela couvre à la fois la filetage Win32 .NET et Native Win32. J'ai écrit des programmes multithreads pendant 10 ans lorsque j'ai découvert ce joyau et j'ai toujours trouvé des choses que je ne connaissais pas dans presque tous les chapitres. P>
En outre, "La modélisation des risques de catastrophe naturelle" ressemble à beaucoup de mathématiques. Peut-être devriez-vous consulter la bibliothèque IPP d'Intel: il fournit des primitives pour de nombreux algorithmes courants de traitement de mathématiques de bas niveau et de signalisation. Il prend en charge plusieurs filets de la boîte, ce qui peut rendre votre tâche de manière significative. p>
simulations de processus numériques sont généralement exécutées sur une seule grille de problème discrétisé (par exemple, le surface de la Terre ou nuages de gaz et de poussières < / a>), ce qui exclut généralement tâche simple agriculture approches ou la concurrence. En effet, une grille divisée sur un ensemble de processeurs représentant une superficie de l'espace disponible est un ensemble de tâches indépendantes. Les cellules de la grille sur le bord de chaque sous-maille besoin être mis à jour sur la base des valeurs de cellules de grille stockées sur d'autres processeurs, qui sont adjacents dans l'espace logique. P>
calcul haute performance, les simulations sont typiquement parallélisé utilisant MPI ou OpenMP . MPI est une bibliothèque qui passe un message avec des liaisons pour de nombreuses langues, y compris C, C ++, Fortran a >, Python et C # . OpenMP est une API pour multitraitement mémoire partagée. En général, MPI est plus difficile à coder que OpenMP, et est beaucoup plus invasive, mais il est aussi beaucoup plus souple. OpenMP nécessite une zone de mémoire partagée entre les processeurs, donc ne convient pas à beaucoup d'architectures. systèmes hybrides sont également possibles. p>
Ce type de programmation a ses propres défis particuliers. Ainsi que conditions de course , les interblocages, cycles non a >, et toutes les autres joies de la programmation simultanée , vous devez considérer le de votre grille de processeur - comment vous choisissez de diviser votre grille logique à travers vos processeurs physiques. Ceci est important parce que votre parallèle est une accélération fonction de la quantité de communication entre vos processeurs, ce qui est lui-même fonction de la longueur d'arête total de la grille décomposée. Comme vous ajoutez d'autres processeurs, cette zone de surface augmente, ce qui augmente la quantité de communication au-dessus . L'augmentation de la granularité finira par devenir prohibitif. P>
L'autre facteur important est la proportion du code qui peut être parallélisé. la loi d'Amdahl dicte alors le maximum théoriquement speedup réalisable. Vous devriez être en mesure d'estimer cela avant de commencer à écrire un code. P>
Ces deux faits coniureront de limiter le nombre maximum de processeurs que vous pouvez exécuter. Le sweet spot peut être plus faible que vous pensez considérablement. P>
Je recommande le livre High Performance Computing, si vous pouvez mettre la main dessus. En particulier, le chapitre sur l'analyse comparative des performances et l'optimisation est inestimable. P>
Une excellente vue d'ensemble en ligne de calcul parallèle, qui couvre les enjeux majeurs, est cette introduction de Lawerence Livermore Laboratoire national . p>
Le modèle que vous choisissez d'utiliser sera dicté par la structure de vos données. Vos données sont-elles bien couplées ou couplées de manière lâche? Si vos données de simulation sont étroitement couplées, vous voudrez examiner OpenMP ou MPI (calcul parallèle). Si vos données sont couplées de manière lâche, un pool d'emplois est probablement un meilleur ajustement ... peut-être même une approche informatique distribuée pourrait fonctionner. p>
Mon conseil est d'obtenir et lisez un texte d'introduction pour vous familiariser avec les différents modèles de concurrence / parallélisme. Regardez ensuite les besoins de votre application et décidez quelle architecture vous devrez utiliser. Après votre connaissance de quelle architecture dont vous avez besoin, vous pouvez regarder des outils pour vous aider. p>
Un livre assez hautement noté qui fonctionne comme une introduction au sujet est "L'art de la concurrence: un guide de filetage de singe pour écrire une application parallèle". P>
Je ne sais pas si cela a été mentionné encore, mais si j'étais à votre place, ce que je ferais en train de faire maintenant (en dehors de la lecture de chaque réponse affichée ici) écrit une application multiple filetée dans votre favori (la plupart utilisé) langue. p>
Je n'ai pas une vaste expérience multithreadée. J'ai joué avec elle dans le passé pour m'amuser, mais je pense que gagner de l'expérience avec une application à deux reprises conviendra à vos efforts futurs. P>
Je vous souhaite bonne chance dans cette entreprise et je dois admettre que j'aurais aimé avoir l'occasion de travailler sur quelque chose comme ça ... P>
Désolé, je veux juste ajouter une réponse pessimiste ou meilleure réaliste ici. P>
Vous êtes sous pression. Date limite de 6 mois et vous ne savez même pas avec certitude quelle langue est ce système et ce qu'il fait et comment il est organisé. Si ce n'est pas un calcul trivial, c'est un très mauvais départ. P>
Plus important encore: vous dites que vous n'avez jamais fait de programmation de MulitithReading auparavant. C'est là que je reçois 4 réveils sonnant à la fois. Le multithreading est difficile et prend beaucoup de temps pour l'apprendre lorsque vous voulez le faire correctement - et vous devez le faire correctement lorsque vous souhaitez gagner une augmentation de vitesse énorme. Le débogage est extrêmement méchant, même avec de bons outils tels que les vues totales de débogueur ou Intels Vtutune. p>
Alors vous dites que vous voulez réécrire l'application dans un autre lanugage - ce n'est pas aussi mauvais que vous devez la réécrire de toute façon. La chance de transformer un seul programme fileté en un puits multithreau à plusieurs personnes sans la refonte totale est presque zéro. P>
Mais d'apprentissage multithreading et une nouvelle langue (quelles sont vos compétences en C ++?) Avec une chronologie de 3 mois (vous devez écrire un prototype de jeton - donc j'ai coupé la période en deux moitiés) est extrêmement difficile. p>
Mon conseil ici est simple et ne l'aimera pas: apprendre des multithreadings maintenant - car c'est une compétence requise dans le futur - mais laissez cet emploi à une personne déjà expérimentée. Eh bien, à moins que vous ne vous souciez pas de réussir sur le programme et que vous recherchez un paiement de 6 mois. P>
Prévoyez-vous une nouvelle écriture de la maintenance originale ou juste?
Pouvez-vous fournir plus d'informations sur le calcul lui-même? Quel type de calcul ce code fait-il? Dans quelle langue est-il écrit? Quel type de structures de données? De quelles méthodes numériques parlons-nous? Combien de temps dure le code?
La seule autorité sur Concurrence IMO . Malheureusement, je n'ai pas suivi la page du cours et je ne peux pas être perpétué à l'état de cette page [d'où commenter, pas de réponse]. Prenez la théorie, appliquez-le à C #.
Apprenez une nouvelle langue tout en concevant un système avec une telle complexité n'est pas un bon choix.
Pourquoi ce marquage est-il c ++? Est-ce l'une des conditions requises pour le projet? Sinon, collez-vous avec une langue que vous connaissez. Pas besoin de rendre plus difficile la tâche que nécessaire.
@Sisiutl Cela fait 8 ans, je suppose que vous avez terminé le projet. Cela vous dérange-t-il de rédiger votre propre réponse sur les tips'n'tricks que vous avez trouvé utiles pour la multithreading?