Asyncio: when use `call_soon`?

Hi community!

In asyncio internals or the internals of other modules that implement features on top of it, there is a lot of loop.call_soon. Does anyone know when call_soon should be used for callbacks, and when callbacks should be called directly?

Example 1: asyncio.Server accepts a connection:

  • BaseSelectorEventLoop._accept_connection creates Task _accept_connection2
  • BaseSelectorEventLoop._accept_connection2
    • creates Future waiter
    • creates _SelectorSocketTransport, passes in waiter
    • awaits waiter
  • _SelectorSocketTransport.__init__
    • call_soon(protocol.connection_made)
    • call_soon(self._add_reader, ...)
    • self._loop.call_soon(futures._set_result_unless_cancelled, waiter, ...)
  • BaseSelectorEventLoop._accept_connection2
    • was awaiting Future waiter, which is now complete

Wouldn’t this do the same without the extra Task, Future, and call_soons?

Example 2: _SelectorSocketTransport receives data from a TCP socket:

  • _SelectorSocketTransport._read_ready calls _read_ready_cb
  • _SelectorSocketTransport._read_ready_cb calls _read_ready__data_received
  • _SelectorSocketTransport._read_ready__data_received calls protocol.data_received

In this case it was elected not to use call_soon even though, arguably, data_received is a callback.