Передача нескольких параметров в пул.функция map () в Python [дубликат]

этот вопрос уже есть ответ здесь:

  • в Python многопроцессорных бассейн.карта для нескольких аргументов 15 ответов

Мне нужен способ использовать функцию в пуле.map (), который принимает более одного параметра. Как я понимаю, целевая функция пула.map() может иметь только одну итерацию в качестве параметра, но есть ли способ, которым я могу передать и другие параметры? В этом случае мне нужно передать несколько переменных конфигурации, таких как my Lock() и logging информацию целевой функции.

Я попытался сделать некоторые исследования, и я думаю, что я могу использовать частичные функции, чтобы заставить его работать? Однако я не совсем понимаю, как они работают. Любая помощь будет очень признательна! Вот простой пример того, что я хочу сделать:

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()

3 ответов


можно использовать functools.partial для этого (как вы и подозревали):

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()

пример:

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()

выход:

hi there 1
hi there 2
hi there 3
hi there 4
hi there 5

вы можете использовать функцию карты, которая позволяет несколько аргументов, как и вилка multiprocessing нашли в 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 позволяет легко вложить иерархические параллельные карты с несколькими входами, поэтому мы можем расширить наш пример, чтобы продемонстрировать это.

>>> 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)]

еще больше удовольствия, чтобы построить вложенную функцию, которую мы можем передать в пул. Это возможно, потому что pathos использует dill, который может сериализовать все что угодно питон.

>>> 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)]

если вы не можете выйти за пределы стандартной библиотеки, однако, вам придется сделать это по-другому. Лучше всего в этом случае использовать multiprocessing.starmap как видно здесь: в Python многопроцессорных бассейн.карта для нескольких аргументов (отмечено @Roberto в комментариях к сообщению OP)

Get pathos здесь:https://github.com/uqfoundation


в случае, если у вас нет доступа к functools.partial, вы также можете использовать функцию-оболочку для этого.

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()

это делает target() в функцию, которая принимает блокировку (или любые параметры, которые вы хотите дать), и она вернет функцию, которая принимает только итерацию в качестве входных данных, но все еще может использовать все ваши другие параметры. Вот что, в конечном счете, передают pool.map(), который затем должен выполнять без проблем.