Python多处理,在重启和阻止僵尸时终止进程的麻烦

时间:2016-04-04 15:02:03

标签: python python-multiprocessing python-3.5

解决方案:

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

os.waitpid(pid, options)

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

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

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

通过观看顶部,我注意到当我重新启动时我正在创建僵尸,所以我创建了终止功能:

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

我从重启开始调用它:

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

然而,僵尸进程仍然存在。因此,经过几个小时的工作后,我意识到在调用函数后添加一个time.sleep周期并将一个局部变量设置为进程'exitcode或打印进程'exitcode将允许进程终止,即使它只是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)时段并且必须引用一个进程'以某种形式或方式进行exitcode以防止它出现僵尸。

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

运行exec('quit')时没有这个问题,只要我终止进程,.join()就不起作用。

有人可以指出我的任何误解吗?我已经尝试过做自己的研究,但没有找到足够的解决方案,而且我知道流程不应该明确终止,因为它们不能很好地退出,但我在工作时间后没有找到其他办法。

很抱歉,我没有提供更多代码,如果需要,我会尽力提供更多代码,这些只是我脚本中相关代码的片段(1000多行)。

1 个答案:

答案 0 :(得分:2)

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

os.waitpid(pid, options)

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