Khi cần chạy blocking code hoặc CPU-bound tasks trong async context:
python
import asyncio
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
# ThreadPoolExecutor — cho blocking I/O trong sync libraries
executor = ThreadPoolExecutor(max_workers=10)
async def call_blocking_lib():
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
executor,
blocking_function, # Không thể await được
arg1, arg2
)
return result
# ProcessPoolExecutor — cho CPU-bound tasks
cpu_executor = ProcessPoolExecutor(max_workers=4)
def heavy_computation(data): # Pure CPU work
return [x**2 for x in data]
async def process_data(large_list):
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
cpu_executor,
heavy_computation,
large_list
)
return result
# asyncio.to_thread (Python 3.9+) — shortcut cho ThreadPool
async def modern_approach():
result = await asyncio.to_thread(blocking_function, arg)Lưu ý: Objects truyền qua ProcessPoolExecutor phải pickle-able.
ThreadPoolExecutor shares memory nhưng bị GIL với CPU-bound tasks.
Run blocking or CPU-bound code inside async context:
python
# ThreadPoolExecutor for blocking sync libraries
executor = ThreadPoolExecutor(max_workers=10)
result = await loop.run_in_executor(executor, blocking_function, arg)
# ProcessPoolExecutor for CPU-bound work
cpu_exec = ProcessPoolExecutor(max_workers=4)
result = await loop.run_in_executor(cpu_exec, heavy_compute, data)
# asyncio.to_thread (Python 3.9+) — shorthand for thread pool
result = await asyncio.to_thread(blocking_function, arg)Pitfall: objects passed to ProcessPoolExecutor must be picklable.