Многопроцессорный пул с «apply_async» ничего не делает, если выполняется изнутри функции - PullRequest
0 голосов
/ 09 июня 2019

Я пытаюсь использовать модуль multiprocessing и, в частности, функцию Pool.apply_async().

Этот код хорошо работает:

import multiprocessing

def do():
    print("Foobar", flush=True)

with multiprocessing.Pool(1) as pool:
    for i in range(2):
        pool.apply_async(do)

    pool.close()
    pool.join()

Строка "Foobar" печатается дважды.

Однако, если я помещу этот код в функцию, а затем вызову эту функцию, ничего не произойдет. Ни ошибки, ни "Foobar", программа завершается беззвучно.

import multiprocessing

def test():

    def do():
        print("Foobar", flush=True)

    with multiprocessing.Pool(1) as pool:
        for i in range(5):
            pool.apply_async(do)

        pool.close()
        pool.join()

test()

Почему это? Я использую Python 3.7.3 в Linux.

1 Ответ

1 голос
/ 09 июня 2019

Чтобы получить результаты вычислений, сделайте следующее изменение в своем коде.

import multiprocessing

def test():

    def do():
        print("Foobar", flush=True)

    with multiprocessing.Pool(1) as pool:
        for i in range(5):
            result = pool.apply_async(do)

            result.get()

        pool.close()
        pool.join()

test()

Вы увидите причину, по которой «ничего не происходит».

Traceback (most recent call last):
  File "/tmp/test.py", line 17, in <module>
    test()
  File "/tmp/test.py", line 12, in test
    result.get()
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 608, in get
    raise self._value
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 385, in _handle_tasks
    put(task)
  File "/usr/lib/python3.5/multiprocessing/connection.py", line 206, in send
    self._send_bytes(ForkingPickler.dumps(obj))
  File "/usr/lib/python3.5/multiprocessing/reduction.py", line 50, in dumps
    cls(buf, protocol).dump(obj)
AttributeError: Can't pickle local object 'test.<locals>.do'    

Python multiprocessing.Pool использует протокол pickle для сериализации данных, которые будут отправлены другому процессу. Протокол pickle может сериализовать только функции верхнего уровня, а не вложенные.

Чтобы узнать, что можно мариновать, а что нет, проверьте документацию .

...