Использование многопроцессорной обработки с runpy - PullRequest
1 голос
/ 08 октября 2019

У меня есть модуль Python, который использует multiprocessing. Я выполняю этот модуль из другого скрипта с runpy. Однако это приводит к тому, что (1) модуль, выполняющий дважды , и (2) задания multiprocessing никогда не завершаются (скрипт просто зависает).

В моем минимальном рабочем примере яиметь скрипт runpy_test.py :

import runpy
runpy.run_module('module_test')

и каталог module_test , содержащий пустой __ init __. py и __ main__.py :

from multiprocessing import Pool

print 'start'
def f(x):
    return x*x
pool = Pool()
result = pool.map(f, [1,2,3])
print 'done'

Когда я запускаю runpy_test.py , я получаю:

start
start

и скрипт зависает.

Если я удаляю вызов pool.map (или если я запускаю __ main __. Py напрямую, включая вызов pool.map), я получаю:

start
done

Я запускаю этов Scientific Linux 7.6 в Python 2.7.5.

Ответы [ 3 ]

1 голос
/ 08 октября 2019

Перепишите ваш __main__.py примерно так:

from multiprocessing import Pool
from .implementation import f

print 'start'
pool = Pool()
result = pool.map(f, [1,2,3])
print 'done'

И затем напишите implementation.py (вы можете вызывать это как хотите), в котором определена ваша функция:

def f(x):
    return x*x

В противном случае у вас будет такая же проблема с большинством интерфейсов в многопроцессорной обработке, независимо от использования runpy. Как объяснил @Weeble, когда Pool.map пытается загрузить функцию f в каждом подпроцессе, он импортирует <your_package>.__main__, где определена ваша функция, но, поскольку у вас есть исполняемый код на уровне модуля в __main__, он будетбыть повторно выполненным подпроцессом.

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

1 голос
/ 08 октября 2019

Попробуйте определить вашу функцию f в отдельном модуле. Он должен быть сериализован для передачи в пул процессов, а затем эти процессы должны воссоздать его, импортировав модуль, в котором он находится. Однако файл __main__.py, в котором он находится, не является модулем или, по крайней мере,не вежливый. Попытка импортировать его приведет к созданию другого пула и другого вызова карты, что похоже на рецепт катастрофы.

0 голосов
/ 08 октября 2019

Хотя это и не «правильный» способ сделать это, одно решение, которое в конечном итоге мне помогло, заключалось в использовании _run_module_as_main runpy вместо run_module. Это было идеально для меня, так как я работал с чужим кодом и требовал наименьшего количества изменений.

...