Неблокирующий генератор на Python

Я использую функцию-генератор из модуля запросов в QT-приложении, почти так же, как в примере с потоками запросов:

import json
import requests

def get_stream():
    r = requests.get('http://httpbin.org/stream/20', stream=True)
    for line in r.iter_lines():
        if line:
            yield json.loads(line)

def consume_stream():
    for message in get_stream():
       #do something

Однако, когда нет входящего ответа (т.е. нерегулярно входящие твиты из Twitters Streaming API), генератор get_stream блокирует метод consume_stream.

Это может произойти в любой ситуации, когда генератор не дает немедленного результата, но может ждать входящих сообщений и т.д., и, следовательно, блокирует пользователя.

Есть ли какой-либо шаблон на Python, где вы можете использовать генератор неблокирующим способом, то есть если генератор дает результат, обрабатывает его, в противном случае делает что-то еще до тех пор, пока не появятся следующие результаты?

Ответ 1

Посмотрите на шаблон производителя-потребителя. Он обычно реализуется в python с помощью Queue.

Производитель, обычно работающий в потоке или другом процессе (Queue поддерживает), просто помещает сообщения в очередь. Потребитель, всякий раз, когда это кажется, выдает сообщения из очереди. Эта операция поддерживает аргумент timeout.

Ответ 2

Как Симеон спрашивает в комментарии, он не может работать так просто, как вы его описываете в своем примере. Есть некоторые детали, о которых вы должны заботиться. Существуют различные решения, которые имеют более или менее смысл, в зависимости от вашего варианта использования. Вы не даете подробных сведений о том, что вы действительно хотите сделать, поэтому я просто отправлю вас в http://twistedmatrix.com/trac/wiki/QTReactor в качестве примера. Существуют разные решения/рамки, которые реализуют очереди асинхронных сообщений. И я думаю, что вы ищете.

Ответ 3

Если вы управляете функцией генератора, одним из решений было бы заставить его генерировать исключение после периода ожидания. Возможно, что-то вроде:

def get_stream(timeout=None):
    while message=read_message(timeout=timout):
        yield message

После этого read_message выкинет TimeOutException или что-то в случае возникновения тайм-аута.

Конечно, вам все равно придется иметь дело с логистикой того, когда/как повторять/возобновлять.