Python队列突然空了

Python Queue suddenly empty

我正在尝试 运行 基于 this example 同时进行一些计算。我扩展它的方式不是简单的功能,而是通过子进程 运行 连接一些外部软件。它是 运行 Python 2.7.6 on Ubuntu 14.04.2 LTS (GNU/Linux 3.16.0-30-generic x86_64).

涉及一个队列来跟踪结果输出。这个队列应该被填满,但在计算完成后似乎是空的。

简化的代码如下所示:

import subprocess, shlex, os, random, pickle
from Queue import Queue
from multiprocessing import Process
from time import sleep

def mp_solve(problems, nprocs):
    def worker(problem, out_q):
        outdict = []
        cmd = "..." + problem
        args = shlex.split(cmd)
        output,error = subprocess.Popen(args,stdout = subprocess.PIPE, stderr= subprocess.PIPE).communicate()
        outdict = [str(problem), str(output)]
        out_q.put(outdict)
        print out_q.empty() #prints False

    out_q = Queue() #create Queue
    procs = []

    for i in range(nprocs):
        p = Process(
                target=worker,
                args=(problems[i][1], out_q))
        procs.append(p)
        p.start()

    sleep(10) #calculations are limited to 3 seconds through a parameter passed to external program

    print out_q.empty() #prints True

    resultlist = []
    for i in range(nprocs):
        print "going to Q" + str(i)
        try:
            resultlist.append(out_q.get())
        except Queue.Empty:
            print "Queue empty"


mp_solve(list_of_problems, 10)

这个输出将是

False
False
False
False
False
False
False
False
False
False
True
going to Q0

最后一个命令后,会话 window 变得无用。我可以输入它,但什么也不会发生,甚至 Ctrl + C 也没有效果。然后我关闭 ssh 会话。

我对多处理还很陌生,我不明白为什么队列似乎被正确填充(从返回的 False 中可以看出)但随后为空。请注意 Queue.Empty 似乎永远不会捕捉到。有什么想法可以让我回到正确的轨道上吗?

Queue 模块中的 Queue 对象不适合多处理:它仅用于同一进程中线程之间的通信。请改用 multiprocessing 模块中的 Queue 对象。

from multiprocessing import Process, Queue

这应该可以解决眼前的问题。这里有一些其他注意事项:

  • out_q.get() 是一个阻塞调用:如果队列中没有任何东西,那么它会等到有。因此,在您上面的代码中,永远不会引发 Empty 异常。对于非阻塞版本,请尝试 out_q.get(block=False)。或者,您可以指定超时:out_q.get(timeout=10.0).

  • 最好在主进程退出之前加入您的子进程。在每个进程上调用 proc.join()。正如 dano 在评论中指出的那样,如果您尝试在 清空队列之前 加入进程,则可能会出现死锁(请参阅警告 here),因此您可能想要在 mp_solve 函数的最后执行此操作。

  • if __name__ == '__main__': 块来保护您的主要代码也是一种很好的做法。它不会对 Linux(在 Python 2.7 下)产生影响,但如果没有它,您的代码将不会 运行 在 Windows.

    [ 上正确=44=]
  • 再次为了跨平台兼容性,您应该将嵌套的 worker 函数移动到模块级别。对于 Windows 上 运行 的代码,worker 函数需要是可 pickle 的,而嵌套函数是不可 pickle 的。