12
mar.
2008
mar.
2008
Programmation multiprocesseurs : les experts s'interrogent
Divers
|
Tags :
hardware
Par Olivier Croisier
La technologie des processeurs multicoeurs se développe à vive allure, pour pallier aux problèmes de montée en fréquence. Les ordinateurs personnels en sont maintenant équipés, ainsi que les dernières consoles de jeu. Mais cette nouvelle architecture impose de nouvelles contraintes : comment répartir les traitements de manière efficace ?
Les experts s'interrogent, et les débats font rage :
- certains préconisent la multiplication de coeurs identiques, facilement programmables et remplaçables ;
- d'autres soutiennent qu'il est préférable de disposer de coeurs différents, spécialisés et optimisés chacun pour une tâche précise, mais plus difficiles à programmer.
Quelle que soit la solution retenue, la répartition et la synchronisation des processus reste une science réellement délicate, et la programmation multi-processeurs ne se démocratisera sans doute qu'avec l'apparition de bibliothèques d'abstraction de haut niveau, masquant tous les détails techniques aux programmeurs.
Commentaires
A mon avis, les bibliothèques de haut niveau ne suffiront pas (tout simplement parce qu'en fait, on les a déjà, ces bibliothèques !). Il faudra plutôt des langages de programmation qui permettent de s'abstraire du caractère forcément séquentiel des algorithmes ou de morceaux d'algorithmes. Pour que la parallélisation ou la bonne exploitation des processeurs soient automatisées par le compilateur (ou l'environnement d'exécution), et ne soit plus du ressort du programmeur.
Par exemple, en Java, aujourd'hui, pour parcourir une collection, on ouvre un itérateur, et on écrit "tant qu'il existe un objet suivant, le prendre et exécuter ces instructions". Ici, l'itération est explicite, et elle est forcément séquentielle, car l’ordre d'itération est lui-même explicite. Paralléliser cette itération est a priori impossible (une étape de l'itération peut utiliser l'objet de l'étape précédente, par exemple).
Pour pouvoir paralléliser le parcours de manière sure et automatisée, il faudrait que l'écriture soit différente : par exemple, en disant quelque chose du genre : "pour chacun des éléments de la collection, exécuter ces instructions sur l'élément" (c'est ce qu'on appelle un itérateur implicite). Du coup, il n'y a plus d'ordre de parcours préétabli, et la collection peut être parcourue dans n'importe quel ordre, voire tous les éléments peuvent être parcourus simultanément par des processeurs (ou des cœurs) différents !
On comprend alors pourquoi le langage C n'a que peu d'avenir dans un monde fortement parallélisé : ce langage a été conçu pour que le programmeur ait un contrôle maximal sur le processeur et ce qu'il exécute. Or les threads et les mutex, c'est un peu le goto de la parallélisation : l’élément de base des structures de contrôle. Et on a besoin de s'en abstraire pour que les programmes soient vraiment fiables. On comprend aussi pourquoi les langages fonctionnels recommencent à avoir du succès. Ils permettent précisément ce que je décris plus haut : éviter autant que possible de présupposer l'ordonnancement des instructions.
Enfin, on comprend mieux les tentatives pour introduire la notion de fermeture (closure en anglais) dans un certain nombre de langages impératifs (Java 7, C++ 0x, ...). Cette notion de closure, qui existe déjà dans des langages impératifs populaires (JavaScript, Scala, Groovy, Ruby, ...), provient des langages fonctionnels, et c'est notamment cette notion qui leur permet de s’abstraire de l’ordonnancement du code.