Problème pour le multithreading avec Python
L'interpréteur courant de Python, CPython, n'est pas à l'aise avec les threads internes c'est pourquoi il dispose d'une mécanique appelé verrou global de l'interpréteur, ou en anglais Global Interpreter Lock (GIL), qui n'autorise qu'un seul fil d'exécution. Concrètement, un processus ne peut pas utiliser plusieurs cœurs CPU en même temps.
En fait, des bibliothèques écrites en C pour des programmes Python ont la possibilité de gérer le GIL et utiliser tous les cœurs CPU disponibles. Néanmoins, l'implémentation de cette fonctionnalité dans une bibliothèque complexifie son code, c'est pourquoi ce n'est pas implanté systématiquement. Des recherches ont donc été menées au cours de ce projet pour trouver des méthodes permettant de mettre en place une véritable solution multithreading, c'est-à-dire des solutions permettant d'inhiber le GIL.
Module Threading de Python
Il existe un module natif de Python permettant d'utiliser les threads internes des CPU. Il s'agit du module Threading et de sa classe Thread. Les processus peuvent contenir plusieurs threads qui partagent le code, les données et les fichiers. De plus tous les threads ont leur propre registre et pile séparée, auxquels ils ont accès. Cependant Threading ne permet pas une exécution strictement parallèle, à cause du verrou de l'interpréteur qui demeure actif. L'utilisation des threads internes ne se fait donc pas de manière simultanée mais Python passe d'un thread à l'autre très rapidement. Ainsi, utiliser cette méthode peut tout de même mener à des gains de performance car elle limite fortement le phénomène de sleeping des threads.
Solutions envisagées
Lors de nos recherches, plusieurs solutions ont été envisagées :
- SWIG : c'est un progiciel de développement permettant de connecter des fonctions et des classes C++ ou C avec des programmes Python.
- concurrent.futures : c'est un paquet permettant de lancer des tâches en parallèle et prenant en charge la répartition de travail entre de multiples processus Python. L''utilisation de la classe ProcessPoolExecutor permet de contourner le GIL et exploiter tous les cœurs CPU disponibles.
- Cython : c'est un langage analogue à Python utilisé pour créer des modules en C pour Python.
Cython
Parmi les solutions envisagées, Cython nous a paru celle qui pouvait le mieux correspondre aux cahier des charges. Cython est un langage de programmation qui permet d'écrire des extensions en C pour des programmes Python. Le code source est traduit en C/C++ optimisé et compilé en tant que modules d’extension Python. D'ailleurs, il est aussi possible d'implémenter des extensions en C++ avec Cython, ce qui était un atout du fait que le C++ est le langage initial de la bibliothèque ROOT.
Le GIL peut être libéré dans une section du code en utilisant la déclaration with nogil. Et inversement, une partie d’une section sans GIL peut y faire appel avec la déclaration with gil. Pour préciser au compilateur que le GIL peut être libéré au sein d’une fonction il faut le spécifier dans son header ou sa déclaration avec l’attribut nogil. Une fois affranchi de cette contrainte, Cython permet de faire du parallélisme avec le module cython.parallel ; il s’agit de parallélisme avec OpenMP.
Figure 4. Schéma de fonctionnement de Cython.
Néanmoins, cette solution n’a pas abouti car la fonction qui permet de libérer le GIL est très restrictive dans son emploi. Il s'est avéré que les sections de code où le GIL est inhibé ne peuvent pas faire appel à des fonctions de Python : seuls des objets C peuvent être appelés. Or, au sein de ce projet, c'est l'interface Python de la bibliothèque ROOT qui est utilisée. Par ailleurs, il a été essayé de plutôt utiliser la bibliothèque ROOT originale. Cependant, les objets de la classe GeoManager déclaré dans le programme en Python ne peuvent pas être utilisé avec le fonction de cette même classe mais codée en C++. Ainsi, la conclusion de cet essai a été que pour obtenir une réelle solution multithreading, un nouvelle maquette devrait être implémentée en utilisant le langage orienté objet C++.
Créez votre propre site internet avec Webador