使用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等杀死父守护进程(即不是Worker)时,孩子们不会死。如何杀死孩子?
我的第一个想法是使用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())
然而,守护进程的孩子们处理起来很棘手,我不得不考虑如何做到这一点的想法和意见。
谢谢。
答案 0 :(得分:31)
您的选择有点受限。如果在self.daemon = True
类的构造函数中执行Worker
无法解决您的问题并尝试捕获父级中的信号(即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是否与最初的PID不同(即,init
或lauchd
采用子进程,因为父进程已经死亡) - 请参阅{ {3}}。但是,如果由于某种原因这不起作用,您可以使用以下函数替换它(改编自reference):
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
答案 1 :(得分:3)
你不能只在第一次创建孩子时存储父pid(让我们说在self.myppid
中),而self.myppid
与getppid()
不同意味着父母死了。< / p>
您还可以使用信号来避免检查父项是否已更改。我不知道python的具体细节,但是像here (at the bottom of the page)所描述的那样可能有用。
答案 2 :(得分:2)
Atexit不会这样做 - 它只能在成功的非信号终止时运行 - 请参阅docs顶部附近的注释。您需要通过两种方法之一设置信号处理。
更容易发声的选项:根据http://docs.python.org/library/multiprocessing.html#process-and-exceptions
在工作进程上设置守护程序标志有点难听的选项:PEP-3143似乎意味着有一种内置的方法来挂钩python-daemon中的程序清理需求。