Concurrency
Table of Contents
1. Concurrency
Concurrency is a concept that allows multiple tasks to overlap without necessarily finishing one before starting the next. One way to achieve this is through parallelism, which is running multiple tasks at the same time. Python, however, has a global interpreter lock. This means that one Python process can only run one line of Python code at a time.
1.1. Coroutines
Instead of running multiple lines at the same time, we can instead use coroutines. Only one coroutine can run at a time, however it can allow another coroutine to run before it has completed by voluntarily using the await keyword. Coroutines can be created with asynchronous functions by defining them with async def:
import asyncio
async def apollo(seconds):
print("Starting Apollo!")
await asyncio.sleep(seconds)
print("Sleep done!")
To run coroutines, we can use asyncio.run():
asyncio.run(apollo(2))
We can also schedule multiple awaitables to be run concurrently with asyncio.gather().
We can make a non-async function run concurrently by using asyncio.to_thread(), like so:
async def unblocking_sleep(seconds):
await asyncio.to_thread(lambda: time.sleep(seconds))
1.2. Shared State
Oftentimes, state is shared between multiple coroutines. This means that after an await is called, it is possible that mutable state is changed by a different coroutine.