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.

Last modified: 2025-10-29 13:57