我想做类似的事情(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技巧)。
答案 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中。
(抱歉,我还不能留下评论,所以我把它写成了一个单独的答案。)