multiprocessing_generator
опирается на многопроцессорный модуль, использующий метод запуска 'fork'
, поскольку предполагается, что вложенная функция wrapped
(определенная в ParallelGenerator
__init__
) может быть передана как target
multiprocessing.Process
объект.На платформе fork
это нормально;дочерний процесс наследует полное состояние родительского объекта (с несколькими небольшими исключениями, такими как потоки), поэтому он имеет равный доступ к вложенной функции wrapped
(в конце концов, он унаследовал точную копию).
Проблема в том, чтов Windows единственным доступным методом запуска является 'spawn'
, для которого требуется, чтобы target
(и все аргументы) были в состоянии pickle
(он их pickle
отправляет, потомку через IPC и восстанавливает ихтам), а вложенные функции никогда не могут pickle
(pickle
, когда функция включает выбор своего квалифицированного имени для импорта и использования на другой стороне, а квалифицированное имя вложенной функции включает не импортируемые компоненты, в этом случае,pickle
ing ParallelGenerator.__init__.<locals>.wrapped
завершается ошибкой, поскольку <locals>
явно не является импортируемым именем).
По сути, multiprocessing_generator
работает только в UNIX-подобных системах и только если вы используете метод запуска по умолчанию('fork'
);если вы вызвали set_start_method
с каким-либо другим значением ('forkserver'
или 'spawn'
), multiprocessing_generator
не сможет работать.
Хотя это ошибка, этоне особенно критическая ошибка в большинстве случаев;у модуля очень мало пользы, если в генераторе должны быть выбраны значения, потому что большинство таких генераторов либо не pickle
способны (например, большинство файловоподобных объектов), либо pickle
требует их запуска до завершения (в этом случае вы потеряли весь свой параллелизм).
Извините, но простой ответ здесь: Не используйте multiprocessing_generator
в Windows.
Этосказал, что если ваш генератор связан с вводом / выводом, вы можете извлечь выгоду из модуля, импортировав его, а затем сразу же исправьте его, чтобы заменить все multiprocessing
компоненты, на которые он полагается, их эквивалентамиmultiprocessing.dummy
имен (которые опираются на потоки и не полагаются на травление), например,
from multiprocessing_generator import ParallelGenerator
import multiprocessing.dummy, multiprocessing_generator
# Monkey-patch to use threads
multiprocessing_generator.Process = multiprocessing.dummy.Process
multiprocessing_generator.Queue = multiprocessing.dummy.Queue
Чтобы было ясно, я не проверял это;никаких гарантий не выражено или подразумевается относительно того, будет ли это работать.Также будет совершенно бессмысленно, если генератор привязан к процессору, по крайней мере, на эталонном интерпретаторе CPython, поскольку генераторы, привязанные к процессору, будут удерживать GIL во время работы, не давая основному потоку выполнять работу, поэтомус таким же успехом мог бы повторяться напрямую.