Appeler du code parallèle depuis cython

comment faire ?

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

J'essaie d’écrire un wrapper pour utiliser une classe cpp en python, j'ai suivi les instructions ici et j'arrive a obtenir un module qui fonctionne depuis python. Le souci est que le code d'origine est conçu pour exploiter tous les coeurs disponibles (OpenMP), et que la version python ne le fait visiblement pas.

Les options de compilations me semblent OK. J'ai essayé d'ajouter des with nogil aux endroits critiques (le GIL bloque également les threads externes ?), mais ça ne règle pas le problème. Quelqu'un sait comment faire ?

Le code de mon .pyx ressemble a ceci :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cdef extern from "../som.h" namespace "som":
    cdef cppclass Som:
        Som(unsigned, unsigned, unsigned)
        void train(vector[sparse_vec]&, unsigned, float, float) nogil

cdef class _Som:
    cdef Som * c_som

    def __cinit__(self, unsigned h, unsigned w, unsigned d):
        self.c_som = new Som(h, w, d)

    def train(self, vector[sparse_vec]& data, unsigned epochs=10, float r0=0, float rN=0.5):
        # python code
        with nogil:
            self.c_som.train(data, epochs, r0, rN)

Et je compile comme ceci :

1
2
3
4
cython --cplus -a _som.pyx
g++ -shared -pthread -fPIC -fwrapv -O2 -Wall -std=c++11 \ 
    -fno-strict-aliasing -fopenmp -I/usr/include/python3.5 \ 
    -o _som.so _som.cpp ../som.cpp ../sparse_vec.cpp

Merci d'avance

Édité par yoch

+0 -0

(le GIL bloque également les threads externes ?)

Non. Le GIL empêche que deux thread de code python s’exécute en parallèle. Si tu met des with nogil CPython va, éventuellement, exécuter un autre thread Python de ton même process (si il y en a) durant l’exécution de ta fonction. Mais il n'a aucune influence sur le reste.

L'erreur vient très certainement de la lib que tu utilise (il faut activer quelque chose au run-time?) ou de la ligne de compilation. Ça va être difficile à dire sans connaitre la lib que tu utilise ou voir son code. Tu as déjà réussi à la faire fonctionner en multi-coeur en dehors de Python ?

+0 -0

Salut, je ne serais pas d'une grande aide parce que n'ai fait que jouer un peu avec OpenMP en C/Fortran mais les options de compilation de g++ ont l'air bonnes, tu n'as pas oublié le -fopenmp. J'imagine que tu n'oublie pas de fixer ta variable d'environnement OMP_NUM_THREADS ou de préciser NUM_THREADS dans la définition de ta région parallèle.

+0 -0
Auteur du sujet

Merci pour vos réponses.

Le code OpenMP vient de moi, et il fonctionne parfaitement avec le programme original. En principe, je n'ai pas besoin de définir OMP_NUM_THREADS et j'obtiens automatiquement le nombre de coeurs disponibles sur ma machine, mais c'est peut-être différent avec python, je vais tester.

Édité par yoch

+0 -0
Auteur du sujet

Re,

J'ai fini par trouver, en fait la partie OpenMP était nickel, c'est une fonction de conversion des données appelée juste avant qui plombait les perfs de manière insensée. J'aurais appris qu'un appel en python pur au milieu d'une boucle cython peut faire très très mal…

+0 -0

Cette réponse a aidé l’auteur du sujet

Ah oui en effet le python au milieu de code natif ça punit assez sévèrement.

En particulier ça t'oblige à réacquérir implicitement le GIL, mais même sans ça : une opération élémentaire en Python est de l'ordre de la micro-seconde, là ou tu mesures tes fonctions en C en nano-secondes.

I was a llama before it was cool

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte