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 pool.map () ne peut avoir qu'un paramètre itérable, mais y a-t-il un moyen de faire passer d'autres paramètres également? Dans ce cas, je dois transmettre quelques variables de configuration, telles que mon Lock () et les informations de journalisation à la fonction cible.
J'ai essayé de faire des recherches et je pense que je pourrais peut-être utiliser des fonctions partielles pour le faire fonctionner? Cependant, je ne comprends pas bien comment cela fonctionne. 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()
Vous pouvez utiliser functools.partial
pour cela (comme vous le soupçonniez):
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 __== "__main__":
main()
Sortie:
hi there 1
hi there 2
hi there 3
hi there 4
hi there 5
Vous pouvez utiliser une fonction de carte qui autorise plusieurs arguments, comme le fait le fork 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 d'imbriquer facilement des cartes parallèles hiérarchiques avec plusieurs entrées. Nous pouvons donc étendre notre exemple pour le 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 le pool. Cela est possible car pathos
utilise dill
, ce qui permet de sérialiser presque tout 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 ne pouvez pas sortir de la bibliothèque standard, vous devrez le faire d'une autre manière. Votre meilleur pari dans ce cas est d'utiliser multiprocessing.starmap
_ comme vu ici: pool.map multitraitement Python pour plusieurs arguments (noté par @Roberto dans les commentaires sur le post de l'OP)
Obtenez pathos
ici: https://github.com/uqfoundation
Si vous n'avez pas accès à functools.partial
, Vous pouvez également utiliser une fonction d'emballage pour cela.
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 transforme target()
en une fonction qui accepte un verrou (ou les paramètres que vous voulez donner), et renvoie une fonction qui prend seulement une valeur itérable en entrée, mais qui peut toujours utiliser tous vos autres paramètres. C'est ce qui est finalement passé à pool.map()
, qui devrait alors s'exécuter sans problème.