python 如何优雅地退出子进程

时间:2022-12-18 11:06:52

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