Faire du parallélisme en python

Utiliser des Threads est extrêmement simple en python, malheureusement ces Threads s’exécuteront sur un seul cœur de votre processeur. C’est dû au GIL (Global Interpreter Lock) de python.

Dès que l’on souhaite utiliser toutes les ressources possibles il faut passer par des Process et utiliser des classes du module multiprocessing qui sont prévues pour être en mémoire partagée (Value, Array, …).

Pour faciliter un cas d’utilisation j’ai mis en place une petite bibliothèque dont voici le code :

class MultiProcessPool(object):
    def __init__(self, operationfunction, values, queuefunction, valres):
        self._operationfunction = operationfunction
        self._queuefunction = queuefunction
        self._values = values
        self._valres = valres
        self._q = Queue()
        self._lock = Lock()
        self._position = Value('i', 0)

    def _processtarget(self):
        """ The method executed in each process """
        while self._position.value < len(self._values):
            #lock and get the current position in the list
            #then add 1 to the current position and unlock
            self._lock.acquire()
            postemp = self._position.value
            self._position.value = self._position.value +1
            self._lock.release()
            #if we are in the boundary of the list use the function
            #created by the user and send the result in the queue
            if postemp < len(self._values):
                #execute the execution function in argument
                #and send the result in the queue
                res = self._operationfunction(self._values[postemp])
                self._q.put(res)

    def _mapqueue(self):
        """ Save all the queue values in the way we want"""
        #for each value in the queue send the value and the temporary
        #result at the function given as argument
        for i in range(0, len(self._values)):
             self._valres = self._queuefunction(self._q.get(),
                                                self._valres)

    def run(self, nbprocess):
        """ do the computation"""
        procs = [ Process(target=self._processtarget, args=())
                 for i in range(0, nbprocess) ]
        for p in procs:
            p.start()
            self._mapqueue()
        for p in procs:
            p.join()
        return self._valres

Les problèmes couverts par MultiProcessPool sont ceux pour lesquels vous avez besoin d’effectuer la même opération sur chaque élément d’une liste. Voici un exemple d’utilisation si vous souhaitez doubler la valeur de tous les éléments d’une liste :

from multiprocesspool.multiprocesspool import MultiProcessPool

def double(value):
    return value * 2
    
def queueop(value, vallistres):
    vallistres.append(value)
    return vallistres
    
if __name__ == "__main__":
    pp = MultiProcessPool(double, [ i for i in range(0,100) ], queueop, [])
    print sorted(pp.run(4)) #run on 4 process

Vous pouvez l’installer avec pip :

pip install microprocesspool

Faire du parallélisme en python par La Réponse est 42 est sous Licence Creative Commons Internationale Attribution-Partage à l'identique 4.0.

Vous aimerez aussi...

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *