Страницы

Поиск по вопросам

понедельник, 8 апреля 2019 г.

Почему пример из документации, для модуля multiprocessing не работает в репл?

Открываю документацию по модулю, копирую второй пример в IDE:
from multiprocessing import Process
def f(name): print('hello', name)
if __name__ == '__main__': p = Process(target=f, args=('bob',)) p.start() p.join()
И получаю вот такой результат:
>>> Traceback (most recent call last): File "", line 1, in File "C:\Python36\lib\multiprocessing\spawn.py", line 105, in spawn_main exitcode = _main(fd) File "C:\Python36\lib\multiprocessing\spawn.py", line 115, in _main self = reduction.pickle.load(from_parent) AttributeError: Can't get attribute 'f' on
Тоже самое происходит и в стандартной IDLE, подскажите в чем может быть проблема?
нашел частичное решение, если вместо multiprocessing использовать multiprocessing.dummy, то кое-что работает, однако все-равно не ясно из за чего это происходит


Ответ

Модуль со скриптом (который процессы создаёт) обязан безопасно импортироваться без запуска новых процессов при использовании spawn (по умолчанию на Windows), forkserver методов запуска. См. пример в документации: Safe importing of main module
Обычно, достаточно if __name__ == '__main__' защиту использовать для частей, которые новые процессы создают. В интерактивном интерпретаторе и в модулях, которые как скрипты выполняются: __name__ == '__main__', поэтому могут ошибки возникать.
Когда вы успешно импортируете f из другого модуля, он не будет назван __main__, поэтому может не возникнуть ошибка (успешный pickle). Подробнее:
для запуска нового процесса, вам нужна функция f чтобы запустить функцию f, Питон должен импортировать модуль её содержащий. В новом процессе у вас ничего нет, кроме встроенных имён. Всё остальное явно импортируется если модуль назван __main__ (скрипт или интерактивный случай), то при импорте if __name__ == '__main__' выполняется и вы пытаетесь рекурсивно ещё новые процессы запустить (fork bomb). В реализации multiprocessing могут некоторые ухищрения присутствовать, чтобы вместо fork bomb исключение возникло (лучше) если модуль не назван __main__, то нет проблем с его импортом. В зависимости от особенностей реализации multiprocessing, текущего окружения, может быть достаточно, если f является pickable (глобальная функция из модуля, который можно импортировать, попадает в эту категорию)
multiprocessing.dummy может работать так как в этом случае создаются новые потоки, а не процессы (все данные общие: глобальная переменная f во всех потоках доступна).

Комментариев нет:

Отправить комментарий