Posted on:
Last modified:
当子进程退出的时候,父进程会收到 SIGCHLD
信号,从而可以采取相应的操作。但是当父进程退出的
时候,系统会把子进程的父进程更改为 pid=0
的 init
进程,却不给子进程发送任何信号。
import os
import time
def loop_print():
import time
while True:
print('child alive, %s' % time.time())
time.sleep(1)
try:
pid = os.fork()
except OSError:
pass
if pid != 0: # parent
print("parent sleep for 2")
time.sleep(2)
print('parent quit')
else:
loop_print()
当父进程退出的时候,子进程一直在不断地 print, 而没有退出。
如果想在父进程退出的时候,让子进程也退出。在 Python 中可以有如下几种做法。
这里的 daemon 和系统的守护进程没有任何关系,是 quit_when_parent_dies 的意思。也就是当父进程
退出的时候,会自动尝试关闭 daemon=True
的子进程。
p = multiprocessing.Process(target=foo, daemon=True)
p.start()
昨天我已经吐槽过标准库的 multiprocessing 有很多坑,不出所望,在这个问题上 multiprocessing 依然提供了半个解法,只解决了一半问题......
正常情况下,当一个程序收到 SIGTERM 或者 SIGHUP 等信号的时候,multiprocessing 会调用每个 子进程的 terminate 方法,这样会给每个子进程发送 SIGTERM 信号,子进程就可以优雅退出。然而, 当异常发生的时候,父进程挂了,比如说收到了 SIGKILL 信号,那么子进程就得不到收割,也就变成了 孤儿进程。
所以说,multiprocessing 库只解决了半个问题,真遇到问题的时候就会坑你一把。
PDEATHSIG
在 Linux 中,进程可以要求内核在父进程退出的时候给自己发信号,使用系统调用 prctl。
prctl(PR_SET_PDEATHSIG, SIGHUP);
在 Python 中也有对应的包 python-prctl,可以在
子进程中这样使用,这样在父进程挂掉的时候,子进程就会收到 SIGHUP
信号:
# apt-get install build-essential libcap-dev
# pip install python-prctl
import signal
import prctl
prctl.set_pdeathsig(signal.SIGHUP)
以上面的程序为例:
import os
import time
def loop_print():
import time
import signal
prctl.set_pdeathsig(signal.SIGTERM)
while True:
print("child alive, %s" % time.time())
time.sleep(1)
try:
pid = os.fork()
except OSError:
pass
if pid != 0: # parent
print("parent sleep for 2")
time.sleep(2)
print("parent quit")
else:
loop_print()
这次我们看到,在父进程退出的同时,子进程也退出了。
parent sleep for 2
child alive, 1539676057.5094635
child alive, 1539676058.5105338
parent quit
缺点:只支持 linux
可以使用 atexit.register
在主进程中注册代码:
# pip install psutil
import psutil
import atexit
import os
import signal
@atexit.register
def kill_children():
print("quitting, press Ctrl-C to force quit")
current_process = psutil.Process()
children = current_process.children(recursive=True)
for child in children:
print("Child pid is {}".format(child.pid))
os.kill(child.pid, signal.SIGTERM)
使用 atexit
在收到 SIGTERM 的时候并不能触发,所以最好使用
signal 注册到主进程对应的信号上。
缺点是当使用 kill -9 或者使用 os._exit
的时候不会调用这些函数。
© 2016-2022 Yifei Kong. Powered by ynotes
All contents are under the CC-BY-NC-SA license, if not otherwise specified.
Opinions expressed here are solely my own and do not express the views or opinions of my employer.
友情链接: MySQL 教程站