Как правильно завершить дочерние процессы с многопроцессорной обработкой в 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, и немного задерживается при выключении. Есть способы очистить кэш, чтобы убедиться, что этого не происходит, но вы, вероятно, не нуждаетесь в них, потому что для большинства приложений очистка кэша происходит достаточно часто автоматически.

стойте на месте.