Python守护进程不终止子进程
在使用 python-daemon 的时候,我是这样创建子进程的:
import multiprocessing
class Worker(multiprocessing.Process):
def __init__(self, queue):
self.queue = queue # we wait for things from this in Worker.run()
...
q = multiprocessing.Queue()
with daemon.DaemonContext():
for i in xrange(3):
Worker(q)
while True: # let the Workers do their thing
q.put(_something_we_wait_for())
当我用 Ctrl-C 或 SIGTERM 等方式杀掉父进程(也就是不是工作进程的那个)时,子进程却没有被杀掉。那怎么才能把子进程也杀掉呢?
我最初的想法是用 atexit 来杀掉所有的工作进程,像这样:
with daemon.DaemonContext():
workers = list()
for i in xrange(3):
workers.append(Worker(q))
@atexit.register
def kill_the_children():
for w in workers:
w.terminate()
while True: # let the Workers do their thing
q.put(_something_we_wait_for())
不过,处理守护进程的子进程是个棘手的事情,我希望能听听大家的想法和建议,看看应该怎么做。
谢谢。
3 个回答
当子进程第一次创建时,你应该保存父进程的ID(我们称之为 self.myppid
)。如果 self.myppid
和 getppid()
不一样,那就说明父进程已经死掉了。
为了避免一直检查父进程是否改变,你可以使用 PR_SET_PDEATHSIG
,这个在 信号文档中有描述。
5.8 Linux的“父进程死亡”信号
每个进程都有一个变量 pdeath_signal,这个变量在调用 fork() 或 clone() 后初始化为 0。它表示当父进程死掉时,子进程应该收到的信号。
在这种情况下,如果你希望子进程也跟着死掉,可以把它设置为 SIGHUP
,像这样:
prctl(PR_SET_PDEATHSIG, SIGHUP);
你的选择有点有限。如果在Worker
类的构造函数中设置self.daemon = True
没有解决问题,而在父进程中尝试捕捉信号(比如SIGTERM
和SIGINT
)也不奏效,你可能需要尝试相反的解决方案——也就是说,不是让父进程杀掉子进程,而是让子进程在父进程死掉时自己“自杀”。
第一步是给Worker
的构造函数传入父进程的PID
(你可以用os.getpid()
来获取)。然后,在工作循环中,不仅仅是执行self.queue.get()
,而是要做一些类似下面的事情:
waiting = True
while waiting:
# see if Parent is at home
if os.getppid() != self.parentPID:
# woe is me! My Parent has died!
sys.exit() # or whatever you want to do to quit the Worker process
try:
# I picked the timeout randomly; use what works
data = self.queue.get(block=False, timeout=0.1)
waiting = False
except queue.Queue.Empty:
continue # try again
# now do stuff with data
上面的解决方案会检查父进程的PID
是否和最开始的不一样(也就是说,如果子进程被init
或launchd
收养了,因为父进程死掉了)——具体可以参考这个链接。不过,如果这个方法出于某种原因不管用,你可以用下面这个函数替代(改编自这里):
def parentIsAlive(self):
try:
# try to call Parent
os.kill(self.parentPID, 0)
except OSError:
# *beeep* oh no! The phone's disconnected!
return False
else:
# *ring* Hi mom!
return True
现在,当父进程死掉时(无论是什么原因),子进程会像苍蝇一样纷纷倒下——正如你所希望的那样,你这个小恶魔!:-D