2012-02-08 31 views
6

Tôi đang cố gắng để thiết lập một hệ thống sản xuất-tiêu dùng đơn giản trong Gevent nhưng kịch bản của tôi không làm lối ra:đề Gevent không kết thúc mặc dù tất cả các mục Queue đang cạn kiệt

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) 

tôi thiên đường' Tôi đã có thể tìm thấy các ví dụ/hướng dẫn tốt về cách sử dụng Gevent vì vậy những gì tôi đã dán ở trên là những gì tôi đã thu thập từ internet.

Nhiều công nhân được kích hoạt, các mục đi vào hàng đợi nhưng ngay cả khi mọi thứ trong hàng đợi kết thúc, chương trình chính không thoát. Tôi phải bấm CTRL^C.

Tôi đang làm gì sai?

Cảm ơn.

Lưu ý phụ: nếu có bất kỳ điều gì mà tập lệnh của tôi có thể được cải thiện, vui lòng cho tôi biết. Những điều đơn giản như kiểm tra khi Hàng đợi trống, v.v.

Trả lời

5

Tôi nghĩ bạn nên sử dụng JoinableQueue như ví dụ từ tài liệu.

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

Bạn có thể giải thích về những gì tôi đã làm sai không? Bạn giải pháp hoạt động tốt nhưng nó sẽ là tốt để biết. Cảm ơn. –

+1

@ MridangAgarwalla, tôi không quá quen thuộc với greenlet internals để xây dựng, nhưng tôi nghĩ 'q.get()' với các tham số mặc định 'block = True, timeout = None' sẽ chặn mãi mãi trên hàng đợi rỗng. Ví dụ, tôi đang sử dụng gevent-1.0b1.win32, và nó tăng 'gevent.hub.LoopExit: Thao tác này sẽ chặn vĩnh viễn' ngoại lệ khi tôi cố gắng' queue.get() 'trên hàng đợi rỗng' trong này http://pastebin.com/mduShJBs – reclosedev

2

Trong nhân viên của bạn, bạn kích hoạt vòng lặp sẽ chạy vĩnh viễn.

Là một mặt lưu ý, một IMHO thanh lịch hơn "mãi mãi loop" có thể được viết chỉ với:

for work_unit in q: 
    # Do work, etc 

gevent.joinall() chờ đợi cho người lao động để hoàn thành; nhưng họ không bao giờ làm, vì vậy chương trình của bạn sẽ mãi mãi chờ đợi. Đây là nguyên nhân khiến nó không thoát.

Nếu bạn không quan tâm đến người lao động nữa, bạn chỉ có thể giết chúng để thay thế:

gevent.killall(workers) 

Một cách khác là đặt một mục 'đặc biệt' trong hàng đợi. Khi một nhân viên nhận được món hàng này, nó nhận ra nó khác với công việc bình thường và ngừng hoạt động.

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

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

Hoặc bạn thậm chí có thể sử dụng sự kiện của gevent để thực hiện loại mẫu này.

+3

Bạn có thể sử dụng 'StopIteration' thay cho chuỗi' "TimeToDie" ', điều này cho phép' for work_unit trong q: 'phá vỡ khi nó đạt đến' StopIteration'. – reclosedev

+0

@reclosedev wow, vâng, đó là một ý tưởng thực sự tốt đẹp. – Ivo

Các vấn đề liên quan