13.13. AsyncIO Event Loop

  • Async code can only run inside an event loop.

  • The event loop is the driver code that manages the cooperative multitasking.

  • You can create multiple threads and run different event loops in each of them.

  • Python will create a default event loop only in Main Thread

  • Python will not create an event loop automatically for you on any other than main thread by default, this is to prevent from having multiple event lops created explicitly

  • Event loop can execute only one callback (coroutine) at a time

  • Some callbacks (coroutines) can schedule themselves once again (trampoline)

  • Reactors

  • Proactors

For example, Django uses the main thread to wait for incoming requests, so we can't run an asyncio event loop there, but we can start a separate worker thread for our event loop [3].

An event loop runs in a thread (typically the main thread) and executes all callbacks and Tasks in its thread. While a Task is running in the event loop, no other Tasks can run in the same thread. When a Task executes an await expression, the running Task gets suspended, and the event loop executes the next Task. [4]


Figure 13.16. Source: Michael Kennedy [1]


Figure 13.17. Source: Michael Kennedy [1]


Figure 13.18. Source: Michael Kennedy [1]


Figure 13.19. Source: Michael Kennedy [1]

13.13.1. Selectors


Figure 13.20. Source: Langa, Ł. import asyncio: Learn Python's AsyncIO [2]


Figure 13.21. Source: Langa, Ł. import asyncio: Learn Python's AsyncIO [2]

13.13.2. Loop

import asyncio

loop = asyncio.new_event_loop()

Return the running event loop in the current OS thread.

If there is no running event loop a RuntimeError is raised. This function can only be called from a coroutine or a callback.

loop = asyncio.get_event_loop()

loop = asyncio.get_event_loop()

from datetime import datetime

def print_now():


def trampoline(name: str = '') -> None:
     print(name, end=' ')
     loop.call_later(0.5, trampoline, name)

loop.call_later(8, loop.stop)

loop.call_soon(trampoline, 'First')
loop.call_soon(trampoline, 'Second')
loop.call_soon(trampoline, 'Third')
loop.call_later(8, loop.stop)

# loop.run_until_complete(future)
#   Run until the future (an instance of Future) has completed.
# loop.run_forever()
#   Run the event loop until stop() is called.
# loop.stop()
#   Stop the event loop.
# loop.is_running()
#   Return True if the event loop is currently running.
# loop.is_closed()
#   Return True if the event loop was closed.
# loop.close()
#   Close the event loop.

# loop.call_soon(callback, *args, context=None)
#   Schedule the callback callback to be called with args arguments at the
# next iteration of the event loop. This method is not thread-safe.
# loop.call_soon_threadsafe(callback, *args, context=None)
#   A thread-safe variant of call_soon(). Must be used to schedule callbacks
# from another thread.

# loop.call_later(delay, callback, *args, context=None)
#   Schedule callback to be called after the given delay number of seconds (
# can be either an int or a float).
# loop.call_at(when, callback, *args, context=None)
#   Schedule callback to be called at the given absolute timestamp when (an
# int or a float), using the same time reference as loop.time().
# loop.time()
#   Return the current time, as a float value, according to the event loop's
# internal monotonic clock.

13.13.3. UVLoop

  • The ultimate loop implementation for UNIXes (run this on production)

$ pip install uvloop
... import uvloop
... uvloop.install()
... loop = asyncio.new_event_loop()
... loop
<uvloop.Loop running=False closed=False debug=False>

13.13.4. References