Python › Concurrency (asyncio/threading/multiprocessing)

How would you use concurrent.futures.ProcessPoolExecutor together with asyncio to run CPU-bound work without blocking the event loop?

Advanced

Answer

Combine loop.run_in_executor() with a ProcessPoolExecutor instance (instead of the default thread pool) to offload genuinely CPU-bound work to a separate PROCESS, bypassing the GIL for true parallelism, while still awaiting the result asynchronously from within your asyncio application.
import asyncio
from concurrent.futures import ProcessPoolExecutor

def cpu_heavy(n):
    return sum(i * i for i in range(n))

async def main():
    loop = asyncio.get_running_loop()
    with ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(pool, cpu_heavy, 10_000_000)
    print(result)
Real-world example Running a CPU-intensive computation (like image processing or numerical analysis) from within an async web server without blocking request handling.

Common follow-ups: Why must arguments passed to a ProcessPoolExecutor's function be picklable, unlike with a ThreadPoolExecutor?