简体   繁体   中英

How to apply keyword-only arguments to a function in a multiprocessing pool?

I have a function that takes a keyword-only argument and want to run it in a process pool. How do I pass my entries from an iterable to the function in the process as a keyword argument?

import multiprocessing

greetees = ('Foo', 'Bar')

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

I tried using multiprocessing.map:

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

But that raises an exception, as expected:

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

It works fine if I remove the asterisk to not require the arguments to be keyword-only:

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

Output:

Hello, Foo!
Hello, Bar!

A solution here is to use Pool.apply or 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)

Output:

Hello, Foo!
Hello, Bar!

Courtesy of Mad Physicist and this QnA , one can use functools.partial to inject keyword-only arguments into a function:

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

Or with less variable bleed:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM