多个消费者,是否可以克隆队列(gevent)?

时间:2012-07-25 07:28:32

标签: python queue gevent

我想做类似的事情(1个队列和多个消费者):

import gevent
from gevent import queue

q=queue.Queue()
q.put(1)
q.put(2)
q.put(3)
q.put(StopIteration)

def consumer(qq):
    for i in qq:
        print i

jobs=[gevent.spawn(consumer,i) for i in [q,q]]

gevent.joinall(jobs)

但是这不可能......队列被job1消耗......所以job2会永远阻止。 它给了我例外gevent.hub.LoopExit: This operation would block forever

我希望每个消费者都可以从头开始使用完整的队列。 (应显示1,2,3,1,2,3或1,1,2,2,3,3 ......没关系)

一个想法应该是在产生之前克隆队列,但是不可能使用copy(浅/深)模块; - (

还有其他办法吗?

[编辑] 你觉得怎么样?

import gevent
from gevent import queue

class MasterQueueClonable(queue.Queue):
    def __init__(self,*a,**k):
        queue.Queue.__init__(self,*a,**k)

        self.__cloned = []
        self.__old=[]

    #override
    def get(self,*a,**k):
        e=queue.Queue.get(self,*a,**k)
        for i in self.__cloned:  i.put(e) # serve to current clones
        self.__old.append(e)              # save old element
        return e

    def clone(self):
        q=queue.Queue()
        for i in self.__old: q.put(i)   # feed a queue with elements which are out
        self.__cloned.append(q)         # stock the queue, to be able to put newer elements too
        return q

q=MasterQueueClonable()
q.put(1)
q.put(2)
q.put(3)
q.put(StopIteration)

def consumer(qq):
    for i in qq:
        print id(qq),i

jobs=[gevent.spawn(consumer,i) for i in [q.clone(), q ,q.clone(),q.clone()]]
gevent.joinall(jobs)

这是基于RyanYe的想法。没有调度程序的“主队列”。 我的主队列覆盖了GET方法,并可以调度到ondemand clone。 而且,在masterqueue开始之后可以创建一个“clone”(使用__old技巧)。

3 个答案:

答案 0 :(得分:2)

我建议你创建一个greenlet来将工作分发给消费者。示例代码:

import gevent
from gevent import queue

master_queue=queue.Queue()
master_queue.put(1)
master_queue.put(2)
master_queue.put(3)
master_queue.put(StopIteration)

total_consumers = 10
consumer_queues = [queue.Queue() for i in xrange(total_consumers)]

def dispatcher(master_queue, consumer_queues):
    for i in master_queue:
        [j.put(i) for j in consumer_queues]
    [j.put(StopIteration) for j in consumer_queues]

def consumer(qq):
    for i in qq:
        print i

jobs=[gevent.spawn(dispatcher, q, consumer_queues)] + [gevent.spawn(consumer, i) for i in consumer_queues]
gevent.joinall(jobs)

更新:修复消费者队列缺少的StopIteration。感谢arilou指出来。

答案 1 :(得分:1)

我有added copy()方法来排队班:

>>> import gevent.queue
>>> q = gevent.queue.Queue()
>>> q.put(5)
>>> q.copy().get()
5
>>> q
<Queue at 0x1062760d0 queue=deque([5])>

如果有帮助,请告诉我。

答案 2 :(得分:0)

在Ryan Ye的回答中,在dispatcher()函数的末尾错过了一行: [message.queues中j的j.put(StopIteration)] 没有它我们仍然得到'gevent.hub.LoopExit:此操作将永远阻止'因为'for master in master_queue'循环不会将StopIteration异常复制到consumer_queues中。

(抱歉,我还不能留下评论,所以我把它写成了一个单独的答案。)