2012-02-08 22 views
6

我想成立GEVENT一個簡單的生產者 - 消費者系統,但我的腳本不退出:GEVENT線程沒有完成,即使所有隊列中的項目都用盡

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

q = Queue() 
workers = [] 

def do_work(wid, value): 
    """ 
    Actual blocking function 
    """ 
    gevent.sleep(random.randint(0,2)) 
    print 'Task', value, 'done', wid 
    return 


def worker(wid): 
    """ 
    Consumer 
    """ 
    while True: 
     item = q.get() 
     do_work(wid, item) 


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


    for item in range(1, 9): 
     q.put(item) 

producer() 
gevent.joinall(workers) 

我的天堂」無法找到使用Gevent的好例子/教程,所以我上面粘貼的是我從互聯網上修補過的東西。

多個工人被激活,物品進入隊列,但即使隊列中的所有物品都完成,主程序也不會退出。我必須按CTRL^C

我在做什麼錯?

謝謝。

附註:如果有任何我的腳本可以改進,請告訴我。簡單的事情,如檢查隊列是空的時候等。

回答

5

我認爲你應該使用JoinableQueue像文檔中的例子。

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

q = JoinableQueue() 
workers = [] 

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: 
      do_work(wid, item) 
     finally: 
      q.task_done() 


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

    for item in range(1, 9): 
     q.put(item) 

producer() 
q.join() 
+0

你能詳細說明我做錯了什麼嗎?你的解決方案工作正常,但它是很好的知道。謝謝。 – 2012-02-08 15:56:23

+1

@MridangAgarwalla,我不太熟悉greenlet的內部細節,但我認爲'q.get()'默認參數'block = True,timeout = None'會在空隊列上永遠阻塞。例如,我使用的是gevent-1.0b1.win32,它引發了'gevent.hub.LoopExit:當我嘗試在這個空的'queue'上嘗試'queue.get()'時,這個操作會永遠阻止異常代碼http://pastebin.com/mduShJBs – reclosedev 2012-02-08 16:58:41

2

在你的工人,你激活一個將永遠運行的循環。

作爲一個側面說明,一個恕我直言,更優雅的「永遠循環」可以只寫:

for work_unit in q: 
    # Do work, etc 

gevent.joinall()等待工作人員來完成;但他們從不這樣做,所以你的程序將永遠等待。這是導致它不能退出的原因。

如果你不關心工人了,你可以殺了他們,而不是:

gevent.killall(workers) 

另一種方法是把一個「特殊」的項目在隊列中。當工人收到這個物品時,它會識別出與正常工作不同並停止工作。

for worker in workers: 
    q.put("TimeToDie") 

for work_unit in q: 
    if work_unint == "TimeToDie": 
     break 
    do_work() 

或者你甚至可以使用gevent的Event來做這種模式。

+3

您可以使用'StopIteration'而不是字符串''TimeToDie'',這允許':work_unit in q:'在到達'StopIteration'時中斷。 – reclosedev 2012-02-09 05:47:54

+0

@reclosedev哇,是的,這真是個好主意。 – Ivo 2012-02-09 11:27:47

相關問題