Python 3: код, исправленный обезьяной, не импортируется повторно при многопроцессорной обработке

Вкратце

Как я могу обезопасить модуль A исправления из модуля B, когда функции модуля A должны быть импортируемыми, чтобы я мог запускать функции модуля A с multiprocessing пакетом стандартной библиотеки?

Задний план

Клиент запросил исправление, которое не будет применимо ни к одному из наших клиентов, поэтому я создал новую ветку и написал отдельный модуль только для них, чтобы упростить слияние изменений из основной ветки. Чтобы поддерживать обратную совместимость клиента с поведением префикса, я реализовал исправление как настраиваемый параметр в приложении. Таким образом, я не хотел заменять свой старый код - просто пропатчил его, когда этот параметр был включен. Я сделал это с помощью исправление обезьян.

Структура кода

Модуль __main__ читает файл конфигурации. Если конфигурация включает переключатель исправления, __main__ исправляет мой engine модуль, заменяя пару функций кодом, определенным в модуле hotfix - по сути, заменяемая функция - это ключевая функция для функции максимизации. Модуль engine позже загружает пул работников multiprocessing.

Проблема

Как только multiprocessing работник начинает работу, первым делом multiprocessing он повторно импортирует * модуль engine и ищет ключевую функцию. который __main__ пытался заменить (затем multiprocessing передает управление моему коду, и начинается алгоритм максимизации). Поскольку engine повторно импортируется совершенно новым процессом, и новый процесс не запускается повторно __main__ (где читается файл конфигурации), потому что это может вызвать бесконечный цикл, он не знает, как повторно обезвредить патч engine .

Вопрос

Как я могу сохранить модульность своего кода (т.е. сохранить код исправления в отдельном модуле) и по-прежнему пользоваться преимуществами пакета Python multiprocessing?

* Обратите внимание, что мой код должен работать в Windows (для моего клиента) и Unix (для моего рассудка ...)


person wkschwartz    schedule 14.09.2012    source источник
comment
+1, красиво оформленный вопрос. Но разве multiprocessing не реимпортируется __main__ в дочерние процессы?   -  person nneonneo    schedule 15.09.2012
comment
@nneonneo, да, но повторный запуск __main__.main() вызовет бесконечный цикл.   -  person wkschwartz    schedule 17.09.2012
comment
Конечно конечно. Но разве нельзя иметь отдельные методы read_config и main() и вызывать read_config, но не main()?   -  person nneonneo    schedule 17.09.2012
comment
Как мне заставить __main__ выяснить, загружается ли он как multiprocessing рабочий или из командной строки?   -  person wkschwartz    schedule 17.09.2012
comment
Смотрите мой ответ. Я считаю, что это должно сделать это за вас.   -  person nneonneo    schedule 17.09.2012


Ответы (3)


Похоже, это место, где исправление обезьян просто не сработает. Проще просто выделить нужные функции в отдельные модули и заставить движок импортировать их оттуда. Возможно, вы сможете настроить конфигурацию того, откуда их импортировать.

Другой способ сделать это по модулям - использовать некую компонентную архитектуру, например ZCA. Я бы выбрал последний вариант, но это потому, что я к нему привык, поэтому мне не нужно учиться дополнительно.

person Lennart Regebro    schedule 15.09.2012

Чтобы заставить его работать в ОС UNIX / Linux, в которой есть fork(), вам не нужно делать ничего особенного, поскольку новый процесс имеет доступ к тем же классам (пропатченным обезьяной), что и родительский.

Чтобы заставить его работать в Windows, пусть ваш __main__ модуль читает конфигурацию при импорте (поместите вызов _3 _ / _ 4_ в глобальную область видимости), но выполняйте многопроцессорную обработку (выполнение движка) в if __name__ == '__main__' guard.

Затем код конфигурации чтения будет выполняться всякий раз, когда __main__ импортируется (либо из командной строки, либо из реимпорта multiprocessing), но код if __name__ == '__main__' выполняется только тогда, когда ваш скрипт вызывается из командной строки (поскольку __main__ повторно импортируется под другое имя в дочернем процессе).

person nneonneo    schedule 17.09.2012

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

Для работы как в UNIX, так и в Windows engine можно сохранить глобальную CONFIG_DONE переменную, чтобы решить, нужно ли снова проверять файл конфигурации.

person Ethan Furman    schedule 14.09.2012