Starlette đẩy hàm def sang một threadpool qua anyio.to_thread.run_sync, nên code đồng bộ không chặn event loop. Threadpool này có giới hạn: AnyIO mặc định 40 thread cho toàn tiến trình.
Hệ quả khi tải cao: request thứ 41 trở đi xếp hàng chờ thread rảnh, latency tăng dần chứ không lỗi. Nếu endpoint def gọi DB đồng bộ mất 200ms thì trần thông lượng của tiến trình xấp xỉ 40 / 0.2 = 200 req/s, bất kể máy còn CPU.
import anyio
@app.on_event("startup")
async def raise_thread_limit():
limiter = anyio.to_thread.current_default_thread_limiter()
limiter.total_tokens = 100Lưu ý trước khi nâng số:
- Thread vẫn tốn stack và context switch; nâng lên vài trăm thường phản tác dụng.
- Pool kết nối DB phải đủ lớn tương ứng, nếu không sẽ chỉ dời điểm nghẽn.
- Event loop vẫn là nơi lập lịch cho các thread này. Nếu loop bị chặn bởi một async def viết sai, request def cũng không được giao thread dù pool đang rỗng.