Как узнать, когда StreamReader готов? - PullRequest
0 голосов
/ 08 мая 2018

Я использую asyncio для установления TCP-соединений:

reader, writer = await asyncio.open_connection(addr)

Мне нужно поддерживать связь. Для этого я храню пару (reader, writer) для будущих сообщений. Однако я не знаю, когда у reader есть данные для чтения. Что я могу с этим сделать? Есть ли способ сделать обработчик, когда ридер готов?

1 Ответ

0 голосов
/ 08 мая 2018

Однако я не знаю, когда у reader есть данные для чтения. Что я могу с этим сделать?

Очевидный способ узнать, когда поток считывателя имеет данные для чтения, - это await it:

data = await reader.read(1024)

Это либо вернет данные сразу, либо приостановит текущую сопрограмму, позволяя другим сопрограммам добиться прогресса, и возобновит ее только тогда, когда у читателя есть какие-то данные для чтения. Вместо того, чтобы хранить устройство чтения / записи для будущего общения, вы можете написать сопрограмму, которая выполняет сообщение, и сохранить задачу 1015 *, которая ее управляет:

async def communicate():
    reader, writer = await asyncio.open_connection(addr)
    # an echo server
    while True:
        line = await reader.readline()
        if not line:
            break
        writer.write(line)
        await writer.drain()  # backpressure, see https://tinyurl.com./hqylfay

task = loop.create_task(communicate())
# the task can itself be awaited, canceled, etc.

Идея asyncio stream API состоит в том, чтобы написать такой последовательный код, оставляя asyncio обрабатывать опросы файловых дескрипторов и планировать задачи. Вы можете использовать комбинаторы, такие как asyncio.gather и asyncio.wait для параллельного запуска тысяч таких легких сопрограмм.

Есть ли способ сделать обработчик, когда ридер готов?

Если вам нужен API на основе обратного вызова, вам, вероятно, следует вместо этого использовать транспорты и протоколы более низкого уровня. Однако, если вы уже работаете с потоками, но все еще время от времени нуждаетесь в обычном обратном вызове, вы можете получить его, получив Future:

future = asyncio.ensure_future(reader.read(1024))
future.add_done_callback(your_callback)

Future имеет роль, эквивалентную обработчику сопрограмм. Как только read больше не будет блокироваться, цикл обработки вызовов будет вызываться циклом обработки событий с единственным аргументом - будущее. Будущее закончится, и его метод result() может быть использован для извлечения полученных данных или исключения.

(Вышеприведенное относится к любому сопрограммному объекту или объекту, совместимому с будущим в asyncio, а не только к StreamReader методам.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...