asyncio (PyPI backport)
The `asyncio` package on PyPI (version 4.0.0) is a deprecated backport of the `asyncio` module, which has been part of Python's standard library since Python 3.4. This PyPI distribution is no longer needed and serves primarily to prevent accidental installation of outdated backports. Users should *not* install this package and instead rely on the built-in `asyncio` module provided by their Python installation.
Warnings
- breaking The `asyncio` package on PyPI is an obsolete backport for Python versions prior to 3.4. Installing it on modern Python (3.4+) can conflict with and break the standard library `asyncio` due to `sys.path` order. Version 4.0.0 and above of the PyPI package contain no code and exist solely to prevent accidental installation of outdated backports; it *should not be installed*.
- deprecated The `@asyncio.coroutine` decorator for defining coroutines was deprecated in Python 3.8 and completely removed in Python 3.10. Using it will result in `SyntaxError` or `DeprecationWarning` depending on the Python version.
- gotcha A very common mistake is calling an `async def` function without `await`ing it. This creates a coroutine object but does not schedule or run it, leading to silent bugs or unexpected behavior (e.g., the code inside the coroutine never executes).
- gotcha `asyncio.run()` cannot be called when an event loop is already running in the current thread. This is a common issue in interactive environments like Jupyter notebooks or when attempting to nest `asyncio.run()` calls.
- breaking Python 3.12 introduced significant changes to `asyncio` affecting task management, exception handling within `TaskGroup`, and cancellation behavior. The `asyncio.get_event_loop()` function became stricter, and `asyncio.run()` now explicitly ensures the event loop and associated resources (like executors and async generators) are properly shut down by default. Code relying on low-level event loop interactions or specific task behavior might encounter breaking changes.
- breaking Python 3.14 changed `asyncio`'s internal implementation in ways that break previous workarounds for nested event loops, notably affecting libraries like `nest_asyncio`. This primarily impacts environments like Jupyter notebooks where an event loop is already active, preventing the automatic async-to-sync conversion previously offered by such workarounds.
- gotcha Using `asyncio.Lock` (or other synchronization primitives like `Semaphore`, `Event`) in a global scope and then repeatedly calling `asyncio.run()` can lead to `RuntimeError`. This happens because `asyncio.run()` creates a new event loop each time, and the global lock object might retain a stale reference to a previously closed loop.
Install
-
pip install asyncio
Imports
- asyncio
import asyncio
Quickstart
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')
await say_after(2, 'world')
print(f"finished at {time.strftime('%X')}")
if __name__ == "__main__":
# The recommended way to run the top-level async function.
asyncio.run(main())