Python 2.7.6中使用多处理的奇怪Queue.PriorityQueue行为

时间:2014-08-15 10:00:03

标签: python queue multiprocessing priority-queue

正如您从标题中所知,我尝试将PriorityQueue与多处理结合使用。更确切地说,我想制作共享的PriorityQueue,编写一些代码并且它没有像我预期的那样运行。

查看代码:

import time
from multiprocessing import Process, Lock
from Queue import PriorityQueue


def worker(queue):
    lock = Lock()
    with lock:
        for i in range(100):
            queue.put(i)

    print "worker", queue.qsize()


pr_queue = PriorityQueue()
worker_process = Process(target = worker, args = (pr_queue,))
worker_process.start()

time.sleep(5)    # nope, race condition, you shall not pass (probably)
print "main", pr_queue.qsize()

得到以下输出:

worker 100
main 0

发生了什么以及如何以正确的方式做我想要的事情? 谢谢。

1 个答案:

答案 0 :(得分:11)

问题不是在这种情况下它不可挑选 - 如果你使用类似Unix的平台,队列可以传递给孩子而不进行酸洗。 (在Windows上,我认为你会在这里遇到酸洗错误)。根本问题是您没有使用进程安全队列。进程之间可以使用的唯一队列是the Queue objects,它们位于multiprocessing模块中。遗憾的是,没有PriorityQueue实施可用。但是,您可以通过注册PriorityQueuemultiprocessing.Manager类轻松创建一个,如下所示:

import time
from multiprocessing import Process
from multiprocessing.managers import SyncManager
from Queue import PriorityQueue


class MyManager(SyncManager):
    pass
MyManager.register("PriorityQueue", PriorityQueue)  # Register a shared PriorityQueue

def Manager():
    m = MyManager()
    m.start()
    return m

def worker(queue):
    print(queue)
    for i in range(100):
        queue.put(i)
    print "worker", queue.qsize()


m = Manager()
pr_queue = m.PriorityQueue()  # This is process-safe
worker_process = Process(target = worker, args = (pr_queue,))
worker_process.start()

time.sleep(5)    # nope, race condition, you shall not pass (probably)
print "main", pr_queue.qsize()

输出:

worker 100
main 100

请注意,这可能不会像标准multiprocessing.Queue子类那样表现得那么好。基于Manager的{​​{1}}是通过创建PriorityQueue服务器进程实现的,该进程实际上包含常规Manager,然后为您的主进程和工作进程提供Proxy在服务器进程中使用IPC读取/写入队列的对象。常规PriorityQueue只是向/ multiprocessing.Queue写入/读取数据。如果这是一个问题,您可以尝试通过从Pipe继承或委派来实现自己的multiprocessing.PriorityQueue。但是,这可能不值得。