2012-02-08 10 views
6

Estoy tratando de establecer un sistema productor-consumidor simple en GEvent pero mi guión no sale:hilos GEvent no terminan a pesar de que todos los elementos de la cola se agotan

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) 

no he Pude encontrar buenos ejemplos/tutoriales sobre el uso de Gevent así que lo que he pegado arriba es lo que he improvisado de Internet.

Se activan varios trabajadores, los elementos van a la cola, pero incluso cuando todo en la cola finaliza, el programa principal no se cierra. Tengo que presionar CTRL^C.

¿Qué estoy haciendo mal?

Gracias.

En una nota al margen: si hay algo que pueda mejorar mi script, por favor avíseme. Cosas simples como verificar cuando la cola está vacía, etc.

Respuesta

5

Creo que debería usar JoinableQueue como en el ejemplo de la documentación.

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

¿Podría explicar lo que estaba haciendo mal? Tu solución funciona bien, pero sería bueno saberlo. Gracias. –

+1

@MridangAgarwalla, no estoy tan familiarizado con las funciones internas de greenlet para elaborar, pero creo que 'q.get()' con los parámetros por defecto 'block = True, timeout = None' bloqueará para siempre en la cola vacía. Por ejemplo, estoy usando gevent-1.0b1.win32, y plantea 'gevent.hub.LoopExit: esta operación bloquearía la excepción forever' cuando intento hacer' queue.get() 'en' cola 'vacía en este código http://pastebin.com/mduShJBs – reclosedev

2

En su trabajador, activa un ciclo que se ejecutará para siempre.

Como nota al margen, una en mi humilde opinión más elegante "para siempre en bucle" se puede escribir con sólo:

for work_unit in q: 
    # Do work, etc 

gevent.joinall() espera a los trabajadores a fin; pero nunca lo hacen, por lo que su programa siempre estará esperando. Esto es lo que hace que no salga.

Si no se preocupan por los trabajadores más, que sólo puede matar a ellos en su lugar:

gevent.killall(workers) 

Una alternativa es poner un elemento 'especial' en la cola. Cuando un trabajador recibe este artículo, lo reconoce como diferente del trabajo normal y deja de funcionar.

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

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

O incluso podría utilizar el evento de gevent para hacer este tipo de patrón.

+3

Puede usar 'StopIteration' en lugar de cadena' "TimeToDie" ', esto permite que' for work_unit in q: 'se rompa cuando llegue a' StopIteration'. – reclosedev

+0

@reclosedev wow, sí, esa es una muy buena idea. – Ivo

Cuestiones relacionadas