Многопроцессорные подпроцессы произвольно получают SIGTERM
Я возлюсь с multiprocessing
а также signal
, Я создаю бассейн, и рабочие должны поймать SIGTERM
s. Без видимых причин я наблюдаю, что подпроцессы получают случайным образом SIGTERM
s. Вот MWE:
import multiprocessing as mp
import signal
import os
import time
def start_process():
print("Starting process #{}".format(os.getpid()))
def sigterm_handler(signo, _frame):
print("Process #{} received a SIGTERM".format(os.getpid()))
def worker(i):
time.sleep(1)
signal.signal(signal.SIGTERM, sigterm_handler)
while True:
with mp.Pool(initializer=start_process) as pool:
pool.map(worker, range(10))
time.sleep(2)
Выход:
Starting process #7735
Starting process #7736
Starting process #7737
Starting process #7738
Starting process #7739
Starting process #7740
Starting process #7741
Starting process #7742
Job done.
Starting process #7746
Starting process #7747
Starting process #7748
Starting process #7749
Starting process #7750
Starting process #7751
Starting process #7752
Starting process #7753
Process #7748 received a SIGTERM
Process #7746 received a SIGTERM
Job done.
Starting process #7757
Starting process #7758
Starting process #7759
Starting process #7760
Starting process #7761
Starting process #7762
Starting process #7763
Starting process #7764
Как видите, это выглядит непредсказуемо.
Итак, где эти SIGTERM
откуда? Это нормально? Я гарантированно, что рабочие закончат свою работу? И в конце концов, нормально ли иметь захват подпроцессов SIGTERM
s?
2 ответа
Это нормально и может произойти во время выполнения вашего пула __exit__
при выходе из контекст-менеджера. Поскольку рабочие уже закончили свою работу, беспокоиться не о чем. Сам бассейн вызывает SIGTERM
для работников, у которых нет кода выхода, когда пул проверяет его. Это срабатывает в Pool._terminate_pool
-метод (Python 3.7.1):
# Terminate workers which haven't already finished.
if pool and hasattr(pool[0], 'terminate'):
util.debug('terminating workers')
for p in pool:
if p.exitcode is None:
p.terminate()
Работники пула присоединятся через несколько строк:
if pool and hasattr(pool[0], 'terminate'):
util.debug('joining pool workers')
for p in pool:
if p.is_alive():
# worker has not yet exited
util.debug('cleaning up worker %d' % p.pid)
p.join()
В сценарии, где вы бы позвонили pool.terminate()
явно, пока ваши работники все еще работают (например, вы используете pool.map_async
а затем использовать pool.terminate()
), ваше приложение будет в тупике в ожидании p.join()
(если вы не позволите sigterm_handler
в конце концов позвоните sys.exit())
,
Лучше не связывайтесь с обработчиками сигналов, если это не нужно.
Я думаю, что это нормально, но ничего не могу сказать о случайной печати сообщений. Вы можете получить больше информации, вставьте это в основной:
mp.log_to_stderr(logging.DEBUG)
и измените start_process():
def start_process():
proc= mp.current_process()
print("Starting process #{}, its name is {}".format(os.getpid(),proc.name))