Passer plusieurs paramètres à la piscine.fonction map () en Python [duplicate]

cette question a déjà une réponse ici:

j'ai besoin d'un moyen d'utiliser une fonction dans pool.map() qui accepte plus d'un paramètre. Selon ma compréhension, la fonction cible de la piscine.map() peut n'avoir qu'un paramètre itérable mais y a-t-il un moyen de passer d'autres paramètres? Dans ce cas, j'ai besoin de passer quelques variables de configuration, comme mon Lock() et les informations de journalisation à la fonction cible.

j'ai essayé de faire quelques recherches et je pense que je peut être en mesure d'utiliser partiellement les fonctions de l'obtenir pour fonctionner? Cependant je ne comprends pas tout de la façon dont ces travaux. Toute aide serait grandement appréciée! Voici un exemple simple de ce que je veux faire:

def target(items, lock):
    for item in items:
        # Do cool stuff
        if (... some condition here ...):
            lock.acquire()
            # Write to stdout or logfile, etc.
            lock.release()

def main():
    iterable = [1, 2, 3, 4, 5]
    pool = multiprocessing.Pool()
    pool.map(target(PASS PARAMS HERE), iterable)
    pool.close()
    pool.join()
36
demandé sur Martijn Pieters 2014-08-28 20:42:46

3 réponses

vous pouvez utiliser functools.partial pour ceci (comme vous le suspectez):

from functools import partial

def target(lock, iterable_item):
    for item in iterable_item:
        # Do cool stuff
        if (... some condition here ...):
            lock.acquire()
            # Write to stdout or logfile, etc.
            lock.release()

def main():
    iterable = [1, 2, 3, 4, 5]
    pool = multiprocessing.Pool()
    l = multiprocessing.Lock()
    func = partial(target, l)
    pool.map(func, iterable)
    pool.close()
    pool.join()

exemple:

def f(a, b, c):
    print("{} {} {}".format(a, b, c))

def main():
    iterable = [1, 2, 3, 4, 5]
    pool = multiprocessing.Pool()
    a = "hi"
    b = "there"
    func = partial(f, a, b)
    pool.map(func, iterable)
    pool.close()
    pool.join()

if __name__ == "__main__":
    main()

sortie:

hi there 1
hi there 2
hi there 3
hi there 4
hi there 5
59
répondu dano 2015-10-28 12:33:33

vous pouvez utiliser une fonction de carte qui permet plusieurs arguments, comme le fait la fourchette de multiprocessing trouvé dans pathos .

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> 
>>> def add_and_subtract(x,y):
...   return x+y, x-y
... 
>>> res = Pool().map(add_and_subtract, range(0,20,2), range(-5,5,1))
>>> res
[(-5, 5), (-2, 6), (1, 7), (4, 8), (7, 9), (10, 10), (13, 11), (16, 12), (19, 13), (22, 14)]
>>> Pool().map(add_and_subtract, *zip(*res))
[(0, -10), (4, -8), (8, -6), (12, -4), (16, -2), (20, 0), (24, 2), (28, 4), (32, 6), (36, 8)]

pathos vous permet de tracer facilement des cartes hiérarchiques parallèles avec des entrées multiples, de sorte que nous pouvons étendre notre exemple pour le démontrer.

>>> from pathos.multiprocessing import ThreadingPool as TPool
>>> 
>>> res = TPool().amap(add_and_subtract, *zip(*Pool().map(add_and_subtract, range(0,20,2), range(-5,5,1))))
>>> res.get()
[(0, -10), (4, -8), (8, -6), (12, -4), (16, -2), (20, 0), (24, 2), (28, 4), (32, 6), (36, 8)]

encore plus amusant, est de construire une fonction imbriquée que nous pouvons passer dans la piscine. Cela est possible parce que pathos utilise dill , qui peut sérialiser presque n'importe quoi en python.

>>> def build_fun_things(f, g):
...   def do_fun_things(x, y):
...     return f(x,y), g(x,y)
...   return do_fun_things
... 
>>> def add(x,y):
...   return x+y
... 
>>> def sub(x,y):
...   return x-y
... 
>>> neato = build_fun_things(add, sub)
>>> 
>>> res = TPool().imap(neato, *zip(*Pool().map(neato, range(0,20,2), range(-5,5,1))))
>>> list(res)
[(0, -10), (4, -8), (8, -6), (12, -4), (16, -2), (20, 0), (24, 2), (28, 4), (32, 6), (36, 8)]

Si vous n'êtes pas en mesure d'aller à l'extérieur de la bibliothèque standard, cependant, vous devrez le faire d'une autre manière. Votre meilleur pari dans ce cas est d'utiliser multiprocessing.starmap comme vu ici: Python multiprocessing pool.carte pour les arguments multiples (noté par @Roberto dans les commentaires sur le post de L'OP)

Get pathos ici: https://github.com/uqfoundation

3
répondu Mike McKerns 2017-05-23 11:46:50

si vous n'avez pas accès à functools.partial , vous pouvez utiliser une fonction d'enrubannage pour cela aussi.

def target(lock):
    def wrapped_func(items):
        for item in items:
            # Do cool stuff
            if (... some condition here ...):
                lock.acquire()
                # Write to stdout or logfile, etc.
                lock.release()
    return wrapped_func

def main():
    iterable = [1, 2, 3, 4, 5]
    pool = multiprocessing.Pool()
    lck = multiprocessing.Lock()
    pool.map(target(lck), iterable)
    pool.close()
    pool.join()

Cela fait de target() une fonction qui accepte une serrure (ou n'importe quels paramètres que vous voulez donner), et il retournera une fonction qui n'accepte qu'une entrée itérable, mais peut toujours utiliser tous vos autres paramètres. C'est ce qui est finalement passé à pool.map() , qui doit s'exécuter sans problème.

0
répondu TheSoundDefense 2014-08-28 16:55:41