tezvyn:

Python Concurrency vs. Parallelism

AI-drafted, machine-checkedSource: docs.python.orgadvanced
Python Concurrency vs. Parallelism

Concurrency is juggling tasks; parallelism is doing them at once. In Python, use concurrency (threading/asyncio) for I/O-bound work like API calls, and parallelism (multiprocessing) for CPU-bound tasks.

WHY IT EXISTS Python's design includes a Global Interpreter Lock (GIL), which simplifies memory management but prevents multiple threads from executing Python code at the same time. This fundamental constraint forces a choice: are you managing tasks that are waiting (I/O-bound), or tasks that are computing (CPU-bound)? The distinction between concurrency and parallelism provides the tools to optimize for each case.

THE MENTAL MODEL Think of a chef in a kitchen. Concurrency is one chef juggling multiple recipes — chopping vegetables for a salad, then stirring a simmering sauce, then checking the oven. They are making progress on everything, but only doing one action at a time. Parallelism is hiring more chefs and giving each their own kitchen; now multiple recipes are being worked on simultaneously.

HOW IT WORKS In Python, concurrency is typically achieved with the threading or asyncio modules. A thread can release the GIL when it's waiting for I/O (like a network response), allowing another thread to run. This makes it efficient for I/O-bound work. asyncio uses a single thread and an event loop to manage tasks, explicitly yielding control during waits.

Parallelism is achieved with the multiprocessing module. It sidesteps the GIL entirely by creating new processes, each with its own Python interpreter and memory space. This allows your code to use multiple CPU cores for true simultaneous execution. The concurrent.futures library provides a high-level interface for both, via its ThreadPoolExecutor (concurrency) and ProcessPoolExecutor (parallelism).

WHEN TO USE IT Use concurrency for applications that spend most of their time waiting for things to happen. Examples include web scrapers, network servers, and applications making many database requests. The program isn't CPU-limited; it's I/O-limited.

Use parallelism for problems that are computationally expensive and can be broken into independent pieces. Examples include video encoding, scientific simulations, and processing large datasets. These tasks can max out a CPU core.

WHEN NOT TO USE IT Do not use threading for CPU-bound tasks, hoping for a speedup on a multi-core machine. The GIL will ensure only one thread runs at a time, and the overhead of thread management will likely make your program slower. Likewise, do not use multiprocessing for simple I/O-bound tasks; the cost of creating and managing processes is much higher than that of threads.

ONE CANONICAL EXAMPLE A modern web application server like FastAPI or Gunicorn uses concurrency to handle thousands of simultaneous client connections. Each connection is mostly I/O-bound (waiting for the request, waiting for the database, sending the response). If a request triggers a heavy, CPU-intensive task like generating a detailed report, the server would offload that work to a separate worker process using a library like multiprocessing to avoid blocking all other concurrent requests.

Read the original → docs.python.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.