web-dev-qa-db-ja.com

asyncioキューコンシューマコルーチン

asyncio.Protocolサーバーからデータを受信するサブクラス。このデータ(データはテキストであるため、各行)をasyncio.Queue

import asyncio

q = asyncio.Queue()

class StreamProtocol(asyncio.Protocol):
    def __init__(self, loop):
        self.loop = loop
        self.transport = None

    def connection_made(self, transport):
        self.transport = transport

    def data_received(self, data):
        for message in data.decode().splitlines():
            yield q.put(message.rstrip())

    def connection_lost(self, exc):
        self.loop.stop()

loop = asyncio.get_event_loop()
coro = loop.create_connection(lambda: StreamProtocol(loop),
                              '127.0.0.1', '42')
loop.run_until_complete(coro)
loop.run_forever()
loop.close()

キュー内のデータを消費して処理する別のコルーチンが必要です。

  • これはasyncio.Task
  • 数秒間データが受信されないためにキューが空になった場合はどうなりますか?消費者が止まらないようにするにはどうすればよいですか(run_until_complete)?
  • キューにグローバル変数を使用するよりもクリーンな方法はありますか?
15
tgy

これはasyncio.Taskである必要がありますか?

はい、 asyncio.ensure_future または loop.create_task を使用して作成します。

数秒間データが受信されないためにキューが空になった場合はどうなりますか?

単に queue.get を使用して、アイテムが利用可能になるまで待機します。

async def consume(queue):
    while True:
        item = await queue.get()
        print(item)

キューにグローバル変数を使用するよりもクリーンな方法はありますか?

はい、単に引数としてコンシューマコルーチンとストリームプロトコルに渡します。

class StreamProtocol(asyncio.Protocol):
    def __init__(self, loop, queue):
        self.loop = loop
        self.queue = queue

    def data_received(self, data):
        for message in data.decode().splitlines():
            self.queue.put_nowait(message.rstrip())

    def connection_lost(self, exc):
        self.loop.stop()

コンシューマーが停止しないようにするにはどうすればよいですか(run_until_complete)?

接続が閉じたら、 queue.join を使用して、キューが空になるまで待機します。


完全な例:

loop = asyncio.get_event_loop()
queue = asyncio.Queue()
# Connection coroutine
factory = lambda: StreamProtocol(loop, queue)
connection = loop.create_connection(factory, '127.0.0.1', '42')
# Consumer task
consumer = asyncio.ensure_future(consume(queue))
# Set up connection
loop.run_until_complete(connection)
# Wait until the connection is closed
loop.run_forever()
# Wait until the queue is empty
loop.run_until_complete(queue.join())
# Cancel the consumer
consumer.cancel()
# Let the consumer terminate
loop.run_until_complete(consumer)
# Close the loop
loop.close()

または、 streams を使用することもできます。

async def tcp_client(Host, port, loop=None):
    reader, writer = await asyncio.open_connection(Host, port, loop=loop)
    async for line in reader:
        print(line.rstrip())
    writer.close()

loop = asyncio.get_event_loop()
loop.run_until_complete(tcp_client('127.0.0.1', 42, loop))
loop.close()
10
Vincent