Python 如何在内核终止时防止多进程僵尸
Python How to prevent multiprocessing zombies when the kernel is terminated
最近我在 Python 中使用多处理时遇到僵尸进程问题。
我有一个脚本可以创建多个进程(工作者)以及另一个进程(打印机)。工作人员将生成消息到队列中,打印机需要打印队列中的所有消息。
问题是工人通常需要工作几个小时。但有时在启动脚本后,我想更改一些代码并重新启动脚本。如果我等到作业完成,就不会有僵尸,因为我使用了 join()。但是,如果我直接关闭内核(因为 ctrl+C 对我的 spyder 不起作用),所有进程(僵尸)仍在工作。
我尝试使用 os.ppid
,但 ppid 似乎没有改变。
我尝试了 p.daemon = True
但它也不起作用。
所以我想问一下有没有办法确保如果我关闭内核,所有进程都会自行终止并且系统中没有僵尸。
谢谢,示例代码是:
from multiprocessing import Process, Queue
import time
def f(num, q):
for i in range(100):
q.put('f: num=%d\n'% (num,))
time.sleep(10)
def g(q, filename):
while True:
with open(filename, 'a') as f:
if q.qsize() > 0:
item = q.get()
if item == None:
break
else:
f.write(item)
def main():
filename = './log.txt'
q = Queue()
workers = [Process(target=f, args=(i,q)) for i in range(10)]
printer = Process(target=g, args=(q,filename))
for p in workers:
p.daemon = True
p.start()
printer.daemon = True
printer.start()
for p in workers:
p.join()
q.put(None)
printer.join()
if __name__ == '__main__':
main()
子进程没有被释放,因为父进程在没有清理的可能性的情况下突然终止。因此,daemon
标志是没有用的。
我不会终止带有 IDE 子进程的进程,因为它可能没有考虑此类用例。我宁愿依靠 OS 设施。
在 Windows 上,您可以将 Taskkill
命令与 /T
参数一起使用。见 taskkill documentation.
在 Linux 上,您可以使用带有 -P
参数的 pkill
命令。 Pkill manpage.
最后的手段是拦截 SIGTERM 信号并将其重新路由为 SIGINT。但是我不推荐这个。
import os
from signal import signal, SIGINT, SIGTERM
def handler(*_):
os.kill(os.pid, SIGINT)
signal.signal(SIGTERM, handler)
这是一个 hack,我什至不确定它是否适用于 Windows。
最近我在 Python 中使用多处理时遇到僵尸进程问题。
我有一个脚本可以创建多个进程(工作者)以及另一个进程(打印机)。工作人员将生成消息到队列中,打印机需要打印队列中的所有消息。
问题是工人通常需要工作几个小时。但有时在启动脚本后,我想更改一些代码并重新启动脚本。如果我等到作业完成,就不会有僵尸,因为我使用了 join()。但是,如果我直接关闭内核(因为 ctrl+C 对我的 spyder 不起作用),所有进程(僵尸)仍在工作。
我尝试使用 os.ppid
,但 ppid 似乎没有改变。
我尝试了 p.daemon = True
但它也不起作用。
所以我想问一下有没有办法确保如果我关闭内核,所有进程都会自行终止并且系统中没有僵尸。
谢谢,示例代码是:
from multiprocessing import Process, Queue
import time
def f(num, q):
for i in range(100):
q.put('f: num=%d\n'% (num,))
time.sleep(10)
def g(q, filename):
while True:
with open(filename, 'a') as f:
if q.qsize() > 0:
item = q.get()
if item == None:
break
else:
f.write(item)
def main():
filename = './log.txt'
q = Queue()
workers = [Process(target=f, args=(i,q)) for i in range(10)]
printer = Process(target=g, args=(q,filename))
for p in workers:
p.daemon = True
p.start()
printer.daemon = True
printer.start()
for p in workers:
p.join()
q.put(None)
printer.join()
if __name__ == '__main__':
main()
子进程没有被释放,因为父进程在没有清理的可能性的情况下突然终止。因此,daemon
标志是没有用的。
我不会终止带有 IDE 子进程的进程,因为它可能没有考虑此类用例。我宁愿依靠 OS 设施。
在 Windows 上,您可以将 Taskkill
命令与 /T
参数一起使用。见 taskkill documentation.
在 Linux 上,您可以使用带有 -P
参数的 pkill
命令。 Pkill manpage.
最后的手段是拦截 SIGTERM 信号并将其重新路由为 SIGINT。但是我不推荐这个。
import os
from signal import signal, SIGINT, SIGTERM
def handler(*_):
os.kill(os.pid, SIGINT)
signal.signal(SIGTERM, handler)
这是一个 hack,我什至不确定它是否适用于 Windows。