6

在研究了 python 守护进程之后,这个遍历似乎是最强大的:http: //www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/

现在我正在尝试在我认为正在工作的守护程序类中实现一个工作池(我没有彻底测试过代码),除了在关闭时我得到一个僵尸进程。我已经读过我需要等待孩子的返回码,但我还不能确切地看到我需要如何做到这一点。

以下是一些代码片段:

def stop(self):
    ...
    try:
        while 1:
            self.pool.close()
            self.pool.join()
            os.kill(pid, SIGTERM)
            time.sleep(0.1)
    ...

在这里,我尝试os.killpg了多种os.wait方法,但没有任何改进。我也玩过closing/joining之前和之后的游泳池os.kill。就目前而言,这个循环永远不会结束,一旦它到达os.kill我就会得到一个僵尸进程。self.pool = Pool(processes=4)发生在__init__守护进程的部分。从run(self)哪个被执行之后start(self),我会打电话self.pool.apply_async(self.runCmd, [cmd, 10], callback=self.logOutput)。但是,我想在研究之前解决这个僵尸进程。

如何正确实现守护进程内的池以避免这个僵尸进程?

4

1 回答 1

4

如果不知道子/守护进程中发生了什么,就不可能对答案有 100% 的信心,但请考虑是否可以。由于您的子进程中有工作线程,因此您实际上需要构建一些逻辑以在收到 SIGTERM 后加入所有这些线程。否则,您的进程可能不会退出(即使退出,您也可能不会正常退出)。为此,您需要:

  • 编写一个信号处理程序以在子/守护进程中使用,该处理程序捕获 SIGTERM 信号并为您的主线程触发一个事件
  • 在子/守护进程的主线程(非常重要)中安装信号处理程序
  • SIGTERM 的事件处理程序必须向子/守护进程中的所有线程发出停止指令
  • 所有线程在完成后都必须加入()(如果您假设 SIGTERM 会自动销毁您可能必须实现此逻辑的所有内容)
  • 一旦所有内容都加入并清理干净,您就可以退出主线程

如果您有用于 I/O 和各种事物的线程,那么这将是一件真正的苦差事。

此外,我通过实验发现,当您使用信号处理程序时,事件侦听器的特定策略很重要。例如,如果您使用 select.select(),则必须使用超时并在超时发生时重试;否则您的信号处理程序将不会运行。如果您有一个用于事件的 Queue.Queue 对象,并且您的事件侦听器调用其 .get() 方法,则必须使用超时,否则您的信号处理程序将不会运行。(在 VM 中用 C 语言实现的“真实”信号处理程序会运行,但您的 Python 信号处理程序不会运行,除非您使用超时。)

祝你好运!

于 2011-06-21T20:26:03.643 回答