asyncio queue consumer coroutine

前端 未结 1 990
广开言路
广开言路 2021-02-13 11:45

I have a asyncio.Protocol subclass receiving data from a server. I am storing this data (each line, because the data is text) in a asyncio.Queue.

1条回答
  •  情歌与酒
    2021-02-13 12:33

    Should this be a asyncio.Task?

    Yes, create it using asyncio.ensure_future or loop.create_task.

    What if the queue becomes empty because for a few seconds no data is received?

    Simply use queue.get to wait until an item is available:

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

    Is there a cleaner way than using a global variable for my queue?

    Yes, simply pass it as argument to the consumer coroutine and stream protocol:

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

    How can I make sure my consumer doesn't stop (run_until_complete)?

    Once the connection is closed, use queue.join to wait until the queue is empty.


    Full example:

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

    Alternatively, you can also use 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()
    

    0 讨论(0)
提交回复
热议问题