Python多处理的输出队列提供的结果比预期的要多

时间:2014-02-07 19:00:30

标签: python queue multiprocessing

从以下代码中我可以预期结果列表的长度与多进程所用的项目范围之一相同:

import multiprocessing as mp

def worker(working_queue, output_queue):
    while True:
        if working_queue.empty() is True:
            break #this is supposed to end the process.
        else:
            picked = working_queue.get()
            if picked % 2 == 0: 
                output_queue.put(picked)
            else:
                working_queue.put(picked+1)
    return

if __name__ == '__main__':
    static_input = xrange(100)    
    working_q = mp.Queue()
    output_q = mp.Queue()
    for i in static_input:
        working_q.put(i)
    processes = [mp.Process(target=worker,args=(working_q, output_q)) for i in range(mp.cpu_count())]
    for proc in processes:
        proc.start()
    for proc in processes:
        proc.join()
    results_bank = []
    while True:
        if output_q.empty() is True:
            break
        else:
            results_bank.append(output_q.get())
    print len(results_bank) # length of this list should be equal to static_input, which is the range used to populate the input queue. In other words, this tells whether all the items placed for processing were actually processed.
    results_bank.sort()
    print results_bank

有没有人知道如何让这段代码正常运行?

1 个答案:

答案 0 :(得分:1)

此代码永远不会停止:

每个工作人员只要不是空的就从队列中获取一个项目:

picked = working_queue.get()

并为每个获得一个新的:

working_queue.put(picked+1)

因此,队列永远不会为空,除非进程之间的时间恰好是在其中一个进程调用empty()时队列为空。因为队列长度最初为100,并且您拥有与cpu_count()一样多的进程,如果在任何实际系统上停止,我会感到惊讶。

通过稍微修改执行代码证明我错了,它确实在某些时候停止,这实际上让我感到惊讶。使用一个进程执行代码似乎存在错误,因为一段时间后进程冻结但不返回。通过多个流程,结果会发生变化。

在循环迭代中添加一个短的睡眠周期使得代码的行为符合我的预期并在上面解释。 Queue.putQueue.getQueue.empty之间似乎存在一些时间问题,尽管它们应该是线程安全的。删除empty测试也会得到预期的结果(不会卡在空队列中)。

找到变化行为的原因。放入队列的对象不会立即刷新。因此,empty可能会返回False,尽管队列中有等待刷新的项目。

来自documentation

  

注意:当一个对象被放入一个队列时,该对象被腌制并且一个   后台线程稍后将pickle数据刷新到底层   管。这有一些后果,但有点令人惊讶   不应该造成任何实际困难 - 如果他们真的很烦   然后,您可以使用由经理创建的队列。

     
      
  1. 将一个对象放在一个空队列之后,在队列的empty()方法返回False之前可能会有一个无穷小的延迟,并且get_nowait()可以返回而不会引发Queue.Empty。

  2.   
  3. 如果多个进程将对象排入队列,则可能无序地在另一端接收对象。但是,由相同进程排队的对象将始终按预期的顺序相互关联。

  4.