如何在Gevent中实现多生产者,多消费者范式?

时间:2012-02-09 12:11:12

标签: python gevent

我有一些生产者函数依赖于I / O重阻塞调用和一些依赖于I / O重阻塞调用的消费者函数。为了加快速度,我使用了Gevent微线程库作为粘合剂。

这就是我的范例:

import gevent
from gevent.queue import *
import time
import random

q = JoinableQueue()
workers = []
producers = []

def do_work(wid, value):
    gevent.sleep(random.randint(0,2))
    print 'Task', value, 'done', wid

def worker(wid):
    while True:
        item = q.get()
        try:
            print "Got item %s" % item
            do_work(wid, item)
        finally:
            print "No more items"
            q.task_done()


def producer():
    while True:
        item = random.randint(1, 11)
        if item == 10:
            print "Signal Received"
            return
        else:
            print "Added item %s" % item
            q.put(item)



for i in range(4):
    workers.append(gevent.spawn(worker, random.randint(1, 100000)))

#This doesnt work.
for j in range(2):
    producers.append(gevent.spawn(producer))

#Uncommenting this makes this script work.
#producer()

q.join()

我有四个消费者,并希望有两个生产者。生产者在他们发出信号即10时退出。消费者继续从这个队列中取食,当生产者和消费者结束时,整个任务就完成了。

然而,这不起作用。如果我注释掉for循环,它生成多个生成器并且只使用一个生成器,那么脚本运行正常。

我似乎无法弄清楚我做错了什么。

有什么想法吗?

由于

4 个答案:

答案 0 :(得分:6)

当队列没有未完成的工作时,你实际上并不想退出,因为从概念上讲,这不是应用程序应该完成的时候。

您希望在制作人完成后退出,然后在没有未完成的工作时退出。

# Wait for all producers to finish producing
gevent.joinall(producers)
# *Now* we want to make sure there's no unfinished work
q.join()
# We don't care about workers. We weren't paying them anything, anyways
gevent.killall(workers)
# And, we're done.

答案 1 :(得分:3)

我认为在将任何内容放入队列并立即退出之前它会q.join()。在加入队列之前尝试加入所有生产者。

答案 2 :(得分:0)

您想要做的是在生产者和工人沟通时阻止主程序。阻塞队列将等待队列为空,然后屈服,这可能是立即的。将其放在程序的末尾而不是q.join()

gevent.joinall(producers)

答案 3 :(得分:0)

我遇到了和你一样的问题。您的代码的主要问题是您的生产者已经在gevent线程中生成,这使得工作者无法立即获得任务。

我建议您应该在主进程中运行producer()而不是在gevent线程中生成当进程运行遇到可以立即推送任务的生产者时。

import gevent
from gevent.queue import *
import time
import random

q = JoinableQueue()
workers = []
producers = []

def do_work(wid, value):
    gevent.sleep(random.randint(0,2))
    print 'Task', value, 'done', wid

def worker(wid):
    while True:
        item = q.get()
        try:
            print "Got item %s" % item
            do_work(wid, item)
        finally:
            print "No more items"
            q.task_done()


def producer():
    while True:
        item = random.randint(1, 11)
        if item == 10:
            print "Signal Received"
            return
        else:
            print "Added item %s" % item
            q.put(item)


producer()

for i in range(4):
    workers.append(gevent.spawn(worker, random.randint(1, 100000)))

以上代码有意义.. :))