Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asyncio: Event vs Future for synchronization

Tags:

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?

like image 784
Radek Kysely Avatar asked Feb 17 '18 01:02

Radek Kysely


People also ask

What is a future in Asyncio?

class asyncio. Future (*, loop=None) A Future represents an eventual result of an asynchronous operation. Not thread-safe. Future is an awaitable object.

What is an Asyncio event?

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.

What is Loop Run_in_executor?

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.

Do you need locks with Asyncio?

You need locks in asyncio as well. Only if you have multiple threads/processes/coroutines sharing resources.


1 Answers

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.

like image 101
Mikhail Gerasimov Avatar answered Sep 20 '22 12:09

Mikhail Gerasimov