When we write applications using multiple threads and multiple processes, we need to worry about race conditions when using non-atomic operations. Something as simple as incrementing an integer concurrently can cause subtle, hard-to-reproduce bugs. When we are using asyncio, however, we’re always using a single thread (unless we’re interoperating with multithreading and multiprocessing), so doesn’t that mean we don’t need to worry about race conditions? It turns out it is not quite so simple.
While certain concurrency bugs that would occur in multithreaded or multiprocessing applications are eliminated by asyncio’s single-threaded nature, they are not completely eliminated. While you likely won’t need to use synchronization often with asyncio, there are still cases where we need these constructs. asyncio’s synchronization primitives can help us prevent bugs unique to a single-threaded concurrency model.