当作业数超过n时,进程无法退出()

时间:2015-03-27 07:53:29

标签: python process queue multiprocessing exit

我正在运行Python 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win32

我生成了4个进程,给它们2个队列 - 用于任务和结果,并在最后加入任务队列。当任务计数达到一定数量时 - 例如njobs = 10000 - 即使所有任务都已完成,一些子进程和主进程也不会退出。

为什么会这样?

用于说明此内容的代码

def worker(job_queue, result_queue):
    import Queue

    while True:
        try:
            j = job_queue.get(False)
        except Queue.Empty:
            exit('done')
        else:
            result_queue.put_nowait(j)
            job_queue.task_done()

if __name__ == "__main__":  
    from multiprocessing import JoinableQueue, Process, cpu_count

    job_queue = JoinableQueue()
    result_queue = JoinableQueue()

    njobs = 10000
    for i in xrange(njobs):
        job_queue.put(i)

    cpus = cpu_count()
    for i in xrange(cpus):
        p = Process(target=worker, args=(job_queue, result_queue))
        p.start()

    job_queue.join()
    print("DONE")

任务越长,某人(或所有)进程挂起所需的任务数就越少。最初,我正在与此进行序列匹配。当队列大约500时,它通常会留下3个进程。

2 个答案:

答案 0 :(得分:1)

显然,队列中包含超过6570项可能会导致死锁(此thread中的更多信息)。你可以做的是在主要执行结束时清空result_queue

while not result_queue.empty():
    result_queue.get(False)
    result_queue.task_done()
print "Done"

请注意,您不必在辅助功能中调用exitreturn就足够了:

except Queue.Empty:
    print "done"
    return

您也可以考虑使用Pool

from multiprocessing import Pool

def task(arg):
    """Called by the workers"""
    return arg

def callback(arg):
    """Called by the main process"""
    pass

if __name__ == "__main__":  
    pool = Pool()
    njobs = 10000
    print "Enqueuing tasks"
    for i in xrange(njobs):
        pool.apply_async(task, (i,), callback=callback)
    print "Closing the pool"
    pool.close()
    print "Joining the pool"
    pool.join()
    print "Done"

答案 1 :(得分:1)

这是Issue 8426: multiprocessing.Queue fails to get() very large objects中详细描述的管道或套接字的实现限制。请注意,它也适用于许多小物件。

<强>解决方案

无论

  • 确保以足够快的速度消耗结果队列
  • 来自子进程的
  • ,请致电Queue.cancel_join_thread()

<强>文档

  

请记住,将项目放入队列的进程将等待   在终止之前,直到所有缓冲的项目都由   “馈线”螺纹到底层管道。 (子进程可以调用   队列的cancel_join_thread()方法可以避免这种行为。)

     

这意味着无论何时使用队列,您都需要确保这一点   所有已放入队列的项目最终都将被删除   在流程加入之前。否则你不能确定   将项目放入队列的进程将终止。记得   此外,非守护进程将自动加入。

- Multiprocessing - Programming guidelines