2012-02-08 7 views
6

Sto cercando di creare un semplice sistema produttore-consumatore in Gevent ma il mio script non esce:discussioni Gevent non finiscono, anche se tutti gli elementi della coda sono esauriti

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) 

Mi rifugio' Sono stato in grado di trovare buoni esempi/tutorial sull'utilizzo di Gevent, quindi quello che ho incollato sopra è quello che ho preso in mano da internet.

Più operatori vengono attivati, gli elementi vanno in coda ma anche quando finisce tutto in coda, il programma principale non esce. Devo premere CTRL^C.

Cosa sto sbagliando?

Grazie.

Nota a margine: se c'è qualcosa che il mio script potrebbe essere migliorato, fatemelo sapere. Cose semplici come controllare quando la coda è vuota, ecc.

risposta

5

Penso che dovresti usare JoinableQueue come nell'esempio dalla documentazione.

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

Potresti approfondire cosa stavo facendo male? La soluzione funziona bene ma sarebbe bene sapere. Grazie. –

+1

@MridangAgarwalla, non sono così familiare con gli interni di greenlet da elaborare, ma penso che 'q.get()' con i parametri predefiniti 'block = True, timeout = None' bloccherà per sempre sulla coda vuota. Ad esempio, sto usando gevent-1.0b1.win32, e solleva 'gevent.hub.LoopExit: questa operazione bloccherà per sempre l'eccezione quando provo a fare' queue.get() 'su' queue' vuota in questo code http://pastebin.com/mduShJBs – reclosedev

2

Nel proprio operatore, si attiva un ciclo che verrà eseguito per sempre.

Come nota a margine, un imho più elegante "per sempre loop" può essere scritto con un semplice:

for work_unit in q: 
    # Do work, etc 

gevent.joinall() attende per i lavoratori per finire; ma non lo fanno mai, quindi il tuo programma ti aspetterà per sempre. Questo è ciò che lo fa non uscire.

Se non si preoccupano i lavoratori più, si può semplicemente uccidere invece:

gevent.killall(workers) 

Un'alternativa è quella di mettere un elemento di 'speciale' in coda. Quando un lavoratore riceve questo oggetto, lo riconosce come diverso dal normale lavoro e smette di funzionare.

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

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

Oppure si potrebbe anche utilizzare Event gevent a fare questo tipo di modello.

+3

Puoi usare 'StopIteration' invece stringhe' "TimeToDie" ', questo permette a' for work_unit in q: 'di interrompere quando raggiungerà' StopIteration'. – reclosedev

+0

@reclosedev wow, sì, è davvero una bella idea. – Ivo

Problemi correlati