Event Loop

Source code: Lib/asyncio/events.py, Lib/asyncio/base_events.py


Preface

The event loop is the core of every asyncio application. Event loops run asynchronous tasks and callbacks, perform network IO operations, and run subprocesses.

Application developers should typically use the high-level asyncio functions, such as asyncio.run(), and should rarely need to reference the loop object or call its methods. This section is intended mostly for authors of lower-level code, libraries, and frameworks, who need finer control over the event loop behavior.

Obtaining the Event Loop

The following low-level functions can be used to get, set, or create an event loop:

asyncio.get_running_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.

New in version 3.7.

asyncio.get_event_loop()

Get the current event loop.

If there is no current event loop set in the current OS thread, the OS thread is main, and set_event_loop() has not yet been called, asyncio will create a new event loop and set it as the current one.

Because this function has rather complex behavior (especially when custom event loop policies are in use), using the get_running_loop() function is preferred to get_event_loop() in coroutines and callbacks.

Consider also using the asyncio.run() function instead of using lower level functions to manually create and close an event loop.

asyncio.set_event_loop(loop)

Set loop as a current event loop for the current OS thread.

asyncio.new_event_loop()

Create a new event loop object.

Note that the behaviour of get_event_loop(), set_event_loop(), and new_event_loop() functions can be altered by setting a custom event loop policy.

Contents

This documentation page contains the following sections:

Event Loop Methods

Event loops have low-level APIs for the following:

Running and stopping the loop

loop.run_until_complete(future)

Run until the future (an instance of Future) has completed.

If the argument is a coroutine object it is implicitly scheduled to run as a asyncio.Task.

Return the Future’s result or raise its exception.

loop.run_forever()

Run the event loop until stop() is called.

If stop() is called before run_forever() is called, the loop will poll the I/O selector once with a timeout of zero, run all callbacks scheduled in response to I/O events (and those that were already scheduled), and then exit.

If stop() is called while run_forever() is running, the loop will run the current batch of callbacks and then exit. Note that new callbacks scheduled by callbacks will not run in this case; instead, they will run the next time run_forever() or run_until_complete() 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.

The loop must not be running when this function is called. Any pending callbacks will be discarded.

This method clears all queues and shuts down the executor, but does not wait for the executor to finish.

This method is idempotent and irreversible. No other methods should be called after the event loop is closed.

coroutine loop.shutdown_asyncgens()

Schedule all currently open asynchronous generator objects to close with an aclose() call. After calling this method, the event loop will issue a warning if a new asynchronous generator is iterated. This should be used to reliably finalize all scheduled asynchronous generators.

Note that there is no need to call this function when asyncio.run() is used.

Example:

try:
    loop.run_forever()
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()

New in version 3.6.

coroutine loop.shutdown_default_executor()

Schedule the closure of the default executor and wait for it to join all of the threads in the ThreadPoolExecutor. After calling this method, a RuntimeError will be raised if loop.run_in_executor() is called while using the default executor.

Note that there is no need to call this function when asyncio.run() is used.

New in version 3.9.

Scheduling callbacks

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.

Callbacks are called in the order in which they are registered. Each callback will be called exactly once.

An optional keyword-only context argument allows specifying a custom contextvars.Context for the callback to run in. The current context is used when no context is provided.

An instance of asyncio.Handle is returned, which can be used later to cancel the callback.

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.

See the concurrency and multithreading section of the documentation.

Changed in version 3.7: The context keyword-only parameter was added. See PEP 567 for more details.

Note

Most asyncio scheduling functions don’t allow passing keyword arguments. To do that, use functools.partial():

# will schedule "print("Hello", flush=True)"
loop.call_soon(
    functools.partial(print, "Hello", flush=True))

Using partial objects is usually more convenient than using lambdas, as asyncio can render partial objects better in debug and error messages.

Scheduling delayed callbacks

Event loop provides mechanisms to schedule callback functions to be called at some point in the future. Event loop uses monotonic clocks to track time.

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).

An instance of asyncio.TimerHandle is returned which can be used to cancel the callback.

callback will be called exactly once. If two callbacks are scheduled for exactly the same time, the order in which they are called is undefined.

The optional positional args will be passed to the callback when it is called. If you want the callback to be called with keyword arguments use functools.partial().

An optional keyword-only context argument allows specifying a custom contextvars.Context for the callback to run in. The current context is used when no context is provided.

Changed in version 3.7: The context keyword-only parameter was added. See PEP 567 for more details.

Changed in version 3.8: In Python 3.7 and earlier with the default event loop implementation, the delay could not exceed one day. This has been fixed in Python 3.8.

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().

This method’s behavior is the same as call_later().

An instance of asyncio.TimerHandle is returned which can be used to cancel the callback.

Changed in version 3.7: The context keyword-only parameter was added. See PEP 567 for more details.

Changed in version 3.8: In Python 3.7 and earlier with the default event loop implementation, the difference between when and the current time could not exceed one day. This has been fixed in Python 3.8.

loop.time()

Return the current time, as a float value, according to the event loop’s internal monotonic clock.

{note}

Changed in version 3.8: In Python 3.7 and earlier timeouts (relative delay or absolute when) should not exceed one day. This has been fixed in Python 3.8.

{tip}

The asyncio.sleep() function.

Creating Futures and Tasks

loop.create_future()

Create an asyncio.Future object attached to the event loop.

This is the preferred way to create Futures in asyncio. This lets third-party event loops provide alternative implementations of the Future object (with better performance or instrumentation).

New in version 3.5.2.

loop.create_task(coro, *, name=None)

Schedule the execution of a Coroutines. Return a Task object.

Third-party event loops can use their own subclass of Task for interoperability. In this case, the result type is a subclass of Task.

If the name argument is provided and not None, it is set as the name of the task using Task.set_name().

Changed in version 3.8: Added the name parameter.