python 如何优雅地退出子进程
主进程产生子进程,子进程进入永久循环模式。当主进程要求子进程退出时,如何能安全地退出子进程呢?
参考一些代码,我写了这个例子。运行之后,用kill pid试试。pid是主进程的pid。当然子进程的也没问题。
1)如果kill pid为子进程的pid,当所有子进程都kill掉了,主进程就关闭了。这也是我们想要的结果。
2)如果kill pid为主进程的pid,主进程向子进程发送退出信号,然后等全部子进程关闭后退出。
保证了主进程在所有子进程退出之后退出。
#-*- coding: UTF-8 -*-# graceful_exit_event.py
# UTF-8 without BOM
#
# refer:
# http://*.com/questions/26414704/how-does-a-python-process-exit-gracefully-after-receiving-sigterm-while-waiting?rq=1
# http://www.cnblogs.com/kaituorensheng/p/4445418.html
# init created: 2016-07-13
# last updated: 2016-07-14
#
#######################################################################
import os
import signal
import multiprocessing
class GracefulExitException(Exception):
@staticmethod
def sigterm_handler(signum, frame):
raise GracefulExitException()
pass
class GracefulExitEvent(object):
def __init__(self):
self.workers = []
self.exit_event = multiprocessing.Event()
# Use signal handler to throw exception which can be caught
# by worker process to allow graceful exit.
signal.signal(signal.SIGTERM, GracefulExitException.sigterm_handler)
pass
def reg_worker(self, wp):
self.workers.append(wp)
pass
def is_stop(self):
return self.exit_event.is_set()
def notify_stop(self):
self.exit_event.set()
def wait_all(self):
while True:
try:
for wp in self.workers:
wp.join()
print "main process(%d) exit." % os.getpid()
break
except GracefulExitException:
self.notify_stop()
print "main process(%d) got GracefulExitException." % os.getpid()
except Exception, ex:
self.notify_stop()
print "main process(%d) got unexpected Exception: %r" % (os.getpid(), ex)
break
pass
#######################################################################
def worker_proc(gee):
import sys, time
print "worker(%d) start ..." % os.getpid()
try:
while not gee.is_stop():
# do task job here
print ".",
time.sleep(1)
else:
print ""
print "worker process(%d) got exit event." % os.getpid()
print "worker process(%d) do cleanup..." % os.getpid()
time.sleep(1)
print "[%d] 3" % os.getpid()
time.sleep(1)
print "[%d] 2" % os.getpid()
time.sleep(1)
print "[%d] 1" % os.getpid()
except GracefulExitException:
print "worker(%d) got GracefulExitException" % os.getpid()
except Exception, ex:
print "Exception:", ex
finally:
print "worker(%d) exit." % os.getpid()
sys.exit(0)
if __name__ == "__main__":
import sys
print "main process(%d) start" % os.getpid()
gee = GracefulExitEvent()
# Start some workers process and run forever
for i in range(0, 10):
wp = multiprocessing.Process(target=worker_proc, args=(gee,))
wp.start()
gee.reg_worker(wp)
gee.wait_all()
sys.exit(0)
需要说明的是:
如果某个进程接受 kill pid,必须在该进程函数的最外层捕获: except GracefulExitException,
同时该进程函数内部调用捕获了 except Excetion,则必须在之前捕获GracefulExitException,
即:
(2) 必须在(3)之前。否则同时去掉(2)和(3)。
def do_some_func(): try: time.sleep(10) blablabla (1) except SomeError: # 捕获特定的异常 pass (2) except GracefulExitException: # 接收 kill pid pass (3) except: # 不建议捕获默认异常, 否则必须在此之前捕获:GracefulExitException passdef some_process_main(gee): try: while not gee.is_stop(): do_some_func() except GracefulExitException: # 接收到了 kill pid, 设置中止循环 gee.notify_stop() pass except: pass