I'm going through some asyncio
source for networking and implementation raised a question in my head.
To create a non-blocking I/O when waiting for the data to arrive from a socket, asyncio.StreamReader.read()
at its end calls _wait_for_data
method that creates an empty Future
and awaits it.
That future is set as finished (which allows it to be finally awaited) in _wakeup_waiter
method that is called when a new data arrives to the stream (feed_data
method).
That makes complete sense.
My question is:
Why not use asyncio.Event
? It feels to me like Event was designed exactly for these purposes. In fact, you wouldn't have to create a new Future on each _wait_for_data
call, but would initialize a single Event in a class and would simply toggle its value during its lifetime. It also has specific .wait()
method for awaiting its value to become True (for when the new data arrives from the socket).
Can anyone elaborate if there's an actual difference between the two approaches? Or is it just a method chosen arbitrarily?
class asyncio. Future (*, loop=None) A Future represents an eventual result of an asynchronous operation. Not thread-safe. Future is an awaitable object.
An asyncio event can be used to notify multiple asyncio tasks that some event has happened. An Event object manages an internal flag that can be set to true with the set() method and reset to false with the clear() method. The wait() method blocks until the flag is set to true.
The loop. run_in_executor() method can be used with a concurrent. futures. ThreadPoolExecutor to execute blocking code in a different OS thread without blocking the OS thread that the event loop runs in.
You need locks in asyncio as well. Only if you have multiple threads/processes/coroutines sharing resources.
While usually you can replace Future
with Event
if you don't care about data future will be populated with, I don't think it's true in this case.
In the code self._waiter
is used not only to indicate wakeup event, but also to indicate exception that happened. set_exception
to Future
means that exact this exception will be raised inside code that awaits for future:
#
waiter.set_exception(exc) # Exception set here...
#
self._waiter = self._loop.create_future()
try:
yield from self._waiter # ... will be raised here and propagated to outer code
finally:
self._waiter = None
You wouldn't be able to achieve this if you change self._waiter
to an Event
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With