Как правильно завершить дочерние процессы с многопроцессорной обработкой в python
у меня есть несколько функций обратного вызова, и я хотел бы запустить как несколько процессов, и все они заканчиваются через сигнал от родительского процесса.
мой текущий способ сделать это-создать общий c_bool с multiprocessing.Value
и значение True
, затем распределяя его на все мои процессы, когда они создаются. Все мои процессы запускают цикл while, используя общий bool следующим образом:
while myC_bool: ...keep running...
Я могу просто переключить bool на False
из моего родительского процесса и все дочерние процессы завершат свой последний цикл и выйдут.
мне говорили многие люди и читали в документах, что при использовании многопроцессорной обработки следует избегать использования общей памяти. Мне сказали, что лучший способ избежать этого-демонизировать процесс, дать ему пользовательский обработчик сигнала и отправить его sigint/sigterm/etc...
мой вопрос заключается в том, что исключительно использует bool для сохранения цикла и только когда-либо изменяет его значение из моего родительского процесса и читает его из нескольких дочерних процессов подходящее решение, чтобы все мои дочерние процессы завершились быстро и безопасно? Я чувствую, что для всех детей меньше накладных расходов, чтобы просто посмотреть на один общий bool, чем отправить им x количество сигинтов.
daemonizing бы быть лучшее решение? Если это так, я хотел бы помочь понять, почему.
3 ответов
есть много хороших причин, чтобы пойти с вашим решением:
- об этом легче думать, чем о сигналах.
- у него меньше кросс-платформенных проблем.
- у тебя уже есть код, который работает таким образом.
- это позволяет легко добавить "изящный механизм выключения", если вы хотите в будущем.
... и так далее.
имейте в виду, что если вы можете доказать себе, что multiprocessing
и базовые примитивы ОС, на каждой платформе, о которой вы заботитесь, гарантированно работают без синхронизации здесь, вам нужно поставить Lock
или что-то еще вокруг каждого доступа к общему bool. Это не совсем сложно, но ... как только вы это сделаете, используя, например,Event
без общего bool может быть еще проще.
в любом случае, если бы какая-то из этих причин была вашей, Я бы сказал, Отлично, сделайте это таким образом. Но согласно вашему вопросу, вы на самом деле выбрали это из-за производительность:
Я чувствую, что есть меньше накладных расходов для всех детей, чтобы просто посмотреть на один общий bool, чем отправить им x количество сигинтов
Если это ваша причина, вы почти наверняка ошибаетесь. Дети должны смотреть на общий bool (и приобретать общий замок!) каждый раз через некоторый цикл, в то время как сигнал должен быть отправлен каждому ребенку только один раз. Таким образом, ваши накладные расходы почти наверняка будут намного выше путь.
но на самом деле, я не могу себе представить, что накладные расходы на отправку одного сигнала на дочерний процесс или даже захват межпроцессной блокировки один раз за цикл на процесс, где-нибудь близко к узкому месту в любой полезной программе, так... почему накладные расходы даже имеют значение здесь в первую очередь? Делайте то, что имеет смысл, самым простым способом.
поскольку вы осторожны с тем, кто изменяет общую переменную, это должно быть хорошо.
возможны различные решения. Е. Г. использовать multiprocessing.Event
, и процессы завершаются, когда он установлен.
Или используя multiprocessing.Connection
объекты (от трубы). Последний может использоваться для двусторонней связи между родителями и детьми. Как сигнал детям остановиться, за которым следует подтверждение родителю.
люди, которые говорят вам "не делай этого" неправильно. Точка общей памяти состоит в том, чтобы делиться памятью между мультипроцессорами, и это именно то, что вы делаете.
У вас есть решение, которое 1) просто, и 2) работает. Подход signal / daemon-это 1) действительно круто и 2) сложнее правильно кодировать и 3) гораздо сложнее понять.
единственная ловушка, которую я вижу в вашем подходе, - это возможность того, что процесс может увидеть устаревшую копию bool из CPU cache, и немного задерживается при выключении. Есть способы очистить кэш, чтобы убедиться, что этого не происходит, но вы, вероятно, не нуждаетесь в них, потому что для большинства приложений очистка кэша происходит достаточно часто автоматически.
стойте на месте.