Au lieu d'ajouter manuellement l'instruction d'extension PLinq AsParallel() manuellement, le compilateur ne peut-il pas le comprendre automatiquement? Y a-t-il des exemples où vous ne voulez pas spécifiquement la parallélisation si le code le supporte?Le compilateur peut-il paralléliser automatiquement le code supportant la parallélisation?
Répondre
Je fais des recherches dans le domaine de la parallélisation automatique. C'est un sujet très délicat qui fait l'objet de nombreux doctorats. dissertations. L'analyse de code statique et la parallélisation automatique ont été faites avec succès pour des langages tels que Fortran, mais il y a des limites à la capacité du compilateur à analyser les dépendances interrégionales. La plupart des gens ne seraient pas prêts à sacrifier la garantie de l'exactitude du code en échange de gains de performance parallèles potentiels, et le compilateur doit donc être assez conservateur lorsqu'il insère des marqueurs parallèles.
Ligne de fond: oui, un compilateur peut paralléliser le code. Mais un humain peut souvent mieux le paralléliser, et demander au compilateur de déterminer où placer les marqueurs peut être très, très, très difficile. Il existe des dizaines de documents de recherche disponibles sur le sujet, tels que le travail de fond pour le compilateur de parallélisation Mitosis ou le travail D-MPI.
La parallélisation automatique est plus complexe qu'elle ne pourrait l'être au départ. C'est ce «si le code le supporte», c'est la partie qui vous attire. Pensez à quelque chose comme
counter = 0
f(i)
{
counter = counter + 1
return i + counter
}
result = map(f, {1,2,3,4})
Si le compilateur décide simplement de paralléliser carte ici, vous pouvez obtenir des résultats différents sur chaque exécution du programme. Certes, il est évident que f ne supporte pas réellement d'être utilisé de cette manière parce qu'il a une variable globale. Cependant, si f est dans un assemblage différent, le compilateur ne peut pas savoir qu'il est dangereux de le paralléliser. Il pourrait introspecter l'assemblage f est à l'exécution et décider alors, mais alors il devient une question de "l'introspection est assez rapide et la parallélisation dynamique assez rapide pour ne pas nier les avantages de faire cela?" Et parfois il ne sera peut-être pas possible d'introspecter, f
pourrait être une fonction P/Invoquée, qui pourrait être parfaitement adaptée à la parallélisation, mais puisque le runtime/compilateur n'a aucun moyen de le savoir il doit supposer qu'il ne peut pas l'être. Ce n'est que la pointe de l'iceberg. En bref, c'est possible, mais difficile, donc le compromis entre la mise en œuvre de la magie et les avantages de la magie étaient probablement biaisés trop loin dans la mauvaise direction.
Les bonnes nouvelles sont que les chercheurs du compilateur disent que nous sommes vraiment près d'avoir paralléliser automatiquement les compilateurs. La mauvaise nouvelle, c'est qu'ils le disent depuis cinquante ans.
Le problème avec les langages impurs tels que C# est généralement qu'il n'y a pas assez de parallélisme. Dans un langage impur, il est très difficile pour un humain et pratiquement impossible pour un programme de comprendre si et comment deux morceaux de code interagissent entre eux ou avec l'environnement.
Dans un pur langage référentielle transparent, vous avez le problème inverse: tout est parallélisables, mais il le fait habituellement pas de sens, parce que la planification d'un fil prend beaucoup plus que juste d'exécuter simplement la fichue chose.
Par exemple, dans un pur référentielle transparent, langage fonctionnel, si j'ai quelque chose comme ceci:
if a <= b + c
foo
else
bar
end
je pourrais tirer jusqu'à cinq fils et calculer a
, b
, c
, foo
et bar
en parallèle , puis je calcule le +
et puis le <=
et enfin, je calcule le if
, ce qui signifie simplement jeter le résultat de foo
ou bar
, qui ont déjà été calculés. (Notez que cela dépend d'être fonctionnel: dans un langage impur, vous ne pouvez pas simplement calculer les deux branches d'un if
et ensuite en jeter un.Que faire si les deux impriment quelque chose? Comment voulez-vous "unprint" cela?)
Mais si a
, b
, c
, foo
et bar
sont vraiment pas cher, puis les frais généraux de ces cinq fils sera beaucoup plus grande que les calculs eux-mêmes.
Quoi qu'il en soit, je l'espère, il y aura des compilateurs intelligents qui prennent soin de ces problèmes parce que je en tant que programmeur ne devrait préciser ce qu'il faut faire et ne pas avoir à se soucier de la façon dont (j'ai assez d'autres problèmes à vous soucier :)). Pourrait être une chance que cela se produise maintenant que les multi-noyaux sont de plus en plus commun – terjetyl
Je suppose que le trickyness du problème dépend un peu de la langue utilisée. Serait-il plus facile de paralléliser des langages fonctionnels tels que F # en raison de leur immutabilité héritée. – terjetyl
@TT, F # est un mauvais exemple, car il est pas « fondamentalement immuable », plutôt immuable est la valeur par défaut (et bien sûr, il peut appeler à d'autres langues CLR de façon transparente). Cela dit, il y a certainement des considérations de conception linguistique comme mutabilité (ou son absence) qui peuvent aider à rendre parallélisation « magique » plus facile –
Est-ce que les langues qui sont par nature immuable existent? – terjetyl