Потоки Gevent не заканчиваются, хотя все элементы очереди исчерпаны - PullRequest
6 голосов
/ 08 февраля 2012

Я пытаюсь настроить простую систему производитель-потребитель в 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.

Что я делаю не так?

Спасибо.

На заметку: если что-то может быть улучшено моим сценарием, пожалуйста, дайте мне знать. Простые вещи, такие как проверка, когда очередь пуста и т. Д.

Ответы [ 2 ]

5 голосов
/ 08 февраля 2012

Я думаю, вы должны использовать 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()
2 голосов
/ 09 февраля 2012

На вашем рабочем месте вы активируете цикл, который будет работать вечно.

В качестве примечания, более элегантный «бесконечный цикл» imho можно записать просто:

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()

Или вы можете даже использовать Event Gevent для создания такого типа шаблона.

...