【问题标题】:Python Multiprocessing, Trouble Terminating Processes on Restart and Preventing ZombiesPython 多处理,在重启和防止僵尸时无法终止进程
【发布时间】:2016-04-04 15:02:02
【问题描述】:

解决方案:

感谢 Rick Sanders,在终止进程后添加此功能解决了问题:

os.waitpid(pid, options)

僵尸进程是在进程终止时创建的,除非它们被收割(通过请求退出代码)。它们保留的目的是让父进程可以请求它的退出代码,并且由于我的脚本没有真正退出,它的进程被execv(file, args) 替换,父进程从不请求退出代码并且僵尸进程被保留。这适用于我的 OSX 和 Debian 系统。

我正在编写一个非常大的脚本,最近实现了多处理和 IMAP 来收听电子邮件。在我实现这个之前,我已经实现了一个重启命令,我可以在命令行输入它以在编辑后刷新脚本,简而言之,它是这样做的:

if ipt = ':rs':
    execv(__file__)

不过,它会在中间打印出一堆废话。

我还有一个在另一个对象中运行的进程,它在一个 While 循环中侦听 Google 的 IMAP 服务器,如下所示:

While True:
    mail = imaplib.IMAP4_SSL('imap.gmail.com')
    mail.login('myemail@gmail', 'mypassword')
    mail.list()
    mail.select("inbox")

    result, data = mail.uid('search', None, 'All')

    latest_email_uid = data[0].split()[-1] #grabs the most recent email by
                                           #unique id number

    if int(latest_email_uid) != int(last_email_uid): # set earlier from sql                         
                                                     # database
        # do stuff with the mail
    else:
        continue

通过看top,我注意到我在重启时正在创建僵尸,所以我创建了一个终止函数:

def process_terminator(self):
    self.imap_listener.terminate()

我从重新开始调用它:

if ipt == ':rs':
    self.process_object.terminate()
    execv(__file__)

但是,僵尸进程仍然存在。因此,经过几个小时的工作,我意识到在调用函数后添加一个 time.sleep 时间段,并且将局部变量设置为进程的退出代码或打印进程的退出代码将允许进程终止,即使它只是0.1 秒:

if ipt == ':rs':
    self.process_object.terminate()
    time.sleep(.1)
    print(self.process_object.imap_listener.exitcode)
    execv(__file__)

这在 OSX 中不是这样,但是,简单地执行一个进程的 .terminate() 函数会结束进程,但是在我的 debian 机器上,我必须有一个 sleep(n) 周期并且必须引用一个进程' 以某种形式或方式退出代码以防止其僵尸化。

我也尝试过使用 .join,尽管这会挂断我的整个脚本。我尝试创建变量以使进程在(例如)self.terminated = 1 时中断其 while 循环,然后加入,但这也不起作用。

我在运行exec('quit')的时候没有这个问题,只要我终止然后处理,.join()就不起作用了。

有人可以指出我的任何误解吗?我已经尝试过自己的研究,但没有找到足够的解决方案,而且我知道进程不应被显式终止,因为它们不会很好地退出,但经过数小时的工作,我没有找到其他方法。

对不起,我没有更多的代码可以提供,如果需要,我会尽力提供更多,这些只是我脚本中相关代码的 sn-ps(1000 多行)。

【问题讨论】:

    标签: python python-multiprocessing python-3.5


    【解决方案1】:

    您可以从这里开始:https://en.wikipedia.org/wiki/Zombie_process。父进程必须在子进程退出时获取子进程,例如使用 waitpid():

    os.waitpid(pid, options)

    等待特定子进程终止并返回已故进程的 pid,如果没有这样的子进程,则返回 -1。在某些系统上,值为 0 表示有进程仍在运行。

    【讨论】:

    • 啊,这就解释了为什么我必须在退出代码从进程表中删除之前阅读它。我会调整我的代码,看看是否能解决它。谢谢!
    • 太棒了!这有效:def process_terminator(self): self.imap_listener.terminate() waitpid(self.imap_listener.pid, 0) 至少在 OSX 上,现在将在我的 debian 系统上试用它......
    猜你喜欢
    • 1970-01-01
    • 2016-03-31
    • 2013-06-05
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 2018-11-27
    • 1970-01-01
    相关资源
    最近更新 更多