Неблокирующий генератор на 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 или что-то в случае возникновения тайм-аута.
Конечно, вам все равно придется иметь дело с логистикой того, когда/как повторять/возобновлять.