У меня есть функция, которая принимает аргумент только для ключевого слова и хочу запустить его в пуле процессов. Как передать мои записи из итерируемой функции в процессе в качестве ключевого аргумента?

import multiprocessing

greetees = ('Foo', 'Bar')

def greet(*, greetee):
    return f'Hello, {greetee}!'

Я попытался использовать multiprocessing.map:

greetings = multiprocessing.Pool(2).map(greet, greetees)
for greeting in greetings:
    print(greeting)

Но это вызывает исключение, как и ожидалось:

multiprocessing.pool.RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/usr/lib/python3.6/multiprocessing/pool.py", line 119, in worker
    result = (True, func(*args, **kwds))
  File "/usr/lib/python3.6/multiprocessing/pool.py", line 44, in mapstar
    return list(map(*args))
TypeError: greet() takes 0 positional arguments but 1 was given
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/bengt/Projekte/gitlab.com/PFASDR/PFASDR.Code.Main/pfasdr/neural/multi_pool_kwargs.py", line 10, in <module>
    greetings = multiprocessing.Pool(2).map(greet, greetees)
  File "/usr/lib/python3.6/multiprocessing/pool.py", line 266, in map
    return self._map_async(func, iterable, mapstar, chunksize).get()
  File "/usr/lib/python3.6/multiprocessing/pool.py", line 644, in get
    raise self._value
TypeError: greet() takes 0 positional arguments but 1 was given

Это работает нормально, если я уберу звездочку, чтобы аргументы не требовали только ключевые слова:

[...]
def greet(greetee):
    return f'Hello, {greetee}!'
[...]

Выход:

Hello, Foo!
Hello, Bar!
0
Bengt 18 Окт 2019 в 18:14

2 ответа

Предоставлено Безумный физик и этот QnA, можно использовать functools.partial для ввода аргументов, содержащих только ключевые слова в функцию:

from functools import partial
greetings = []
for i in range(len(greetees)):
    kwargs = {'greetee': greetees[i]}
    greet_partial = partial(greet, **kwargs)
    greetings.append(multiprocessing.Pool(2).apply(greet_partial))

Или с менее переменным кровотечением:

from functools import partial
greetings = [
    multiprocessing.Pool(2).apply(
        partial(greet, **{'greetee': greetees[i]})
    )
    for i in range(len(greetees))
]
0
Bengt 18 Окт 2019 в 19:07

Решение здесь - использовать Pool.apply или Pool.apply_async:

greetings = list(
    multiprocessing.Pool(2).apply(greet, kwds={'greetee': greetees[i]})
    for i in range(len(greetees))
)
for greeting in greetings:
    print(greeting)

Выход:

Hello, Foo!
Hello, Bar!
1
Bengt 18 Окт 2019 в 18:20
Это должен быть принятый ответ или есть лучший способ?
 – 
Bengt
18 Окт 2019 в 18:16
Спасибо, я видел этот ответ, но не понял, что он связан с той же проблемой. Да, действительно работает. Я отправлю другой ответ.
 – 
Bengt
18 Окт 2019 в 18:33
Вы должны написать в другом вопросе. Вы согласны с тем, что ваш по сути дубликат?
 – 
Mad Physicist
18 Окт 2019 в 18:34
Нет, не думаю, что это дубликаты. Они пытаются передать функции 3 статических аргумента ключевого слова (b, c, d), используя functools.partial и один (a) в качестве позиционного аргумента, используя Pool.map. Я не могу сделать последнее, потому что аргумент моей функции состоит только из ключевых слов. Следовательно, я могу передать аргумент только с ключевым словом, используя apply или apply_async.
 – 
Bengt
18 Окт 2019 в 18:54