I'm using asyncio
to make TCP connections:
reader, writer = await asyncio.open_connection(addr)
I need to keep connections alive. For this, I'm storing a pair of (reader, writer)
for future communications. However, I don't know when reader
has data to read. What can I do with it? Is there a way to make a handler, when the reader is ready?
The obvious way to know when a reader stream has data to read is to
await
it:This will either return the data right away, or suspend the current coroutine, allowing other coroutines to make progress, and only resuming this one when the reader has some data to read. Instead of storing the reader/writer for future communication, you can write a coroutine that does the communication, and store the task that drives it:
The idea behind the asyncio stream API is to write such sequential-looking code, leaving it to asyncio to handle polling of file descriptors and scheduling of tasks. You can use combinators like
asyncio.gather
andasyncio.wait
to run thousands of such lightweight coroutines in parallel.If you need a callback-based API, you should probably use the lower-level transports and protocols instead. However, if you are already working with streams, but still occasionally need an ordinary callback, you can get it by obtaining a
Future
:Future has the role equivalent to a coroutine handler. Once
read
would no longer block, the done-callback will be invoked by the event loop with a single argument, the future. The future will have finished, and itsresult()
method can be used to retrieve the received data or an exception.(The above applies to any coroutine or future-compatible object in asyncio, not just to
StreamReader
methods.)