- vừa được xem lúc

[FastAPI] Tránh block event loop: Hướng dẫn async đúng cách

0 0 4

Người đăng: anhnd

Theo Viblo Asia

Trong bài viết này, mình sẽ chia sẻ lại quá trình tìm hiểu của bản thân về cách hoạt động của async/await trong FastAPI, từ những ví dụ cơ bản đến cách mà các tác vụ bất đồng bộ vận hành bên dưới thông qua event loop. Mình tin rằng đây là chủ đề dễ gây nhầm lẫn khi mới làm việc với Python async hoặc FastAPI.

Note: Bài viết được biên soạn dựa trên quá trình tìm hiểu cá nhân, có sử dụng AI (ChatGPT) để hỗ trợ giải thích và sắp xếp nội dung cho dễ hiểu hơn.


1. Tình huống ban đầu: một đoạn code bất thường

Giả sử bạn có một API FastAPI như sau:

from fastapi import FastAPI
import time
import asyncio app = FastAPI() @app.get("/bad_async")
async def bad_async(): time.sleep(5) return {"msg": "bad async"} @app.get("/slow")
async def slow_non_blocking(): await asyncio.sleep(5) return {"msg": "done"} @app.get("/quick")
async def quick(): return {"msg": "quick response"}

Nếu bạn gọi API /bad_async trước, rồi ngay sau đó gọi tiếp /quick, thì /quick sẽ bị chặn 5 giây. Nhưng nếu thay vào đó là gọi /slow rồi gọi /quick, thì /quick phản hồi ngay lập tức. Tại sao lại có sự khác biệt như vậy?

📚 Tài liệu tham khảo – FastAPI: Async and Await


2. Event loop là gì?

Giải thích đơn giản

Hãy tưởng tượng event loop giống như một nhân viên trực tổng đài, nhiệm vụ là:

  • Lần lượt nhận các yêu cầu đến.
  • Giao nhiệm vụ cho các tác vụ có thể xử lý ngay.
  • Nếu tác vụ đang chờ đợi một thứ gì đó (I/O), thì nó nhường lại quyền xử lý cho tác vụ khác.

📚 Python Docs – asyncio Event Loop

Minh họa thực tế

  • await asyncio.sleep(5) giống như một người nói: “Tôi đang chờ 5 giây, ai khác cần xử lý gì thì vào trước đi”.
  • time.sleep(5) giống như một người chiếm luôn ghế 5 giây, dù không làm gì cả.

Kết quả là khi event loop gặp await asyncio.sleep(5) → nó chuyển sang xử lý tiếp những việc khác (ví dụ /quick). Nhưng gặp time.sleep(5) → bị đứng hình toàn bộ.


3. Vì sao đổi async def thành def thì lại không bị block?

Nếu bạn sửa lại đoạn code:

@app.get("/bad_async")
def bad_async(): time.sleep(5) return {"msg": "bad async"}

Thì bất ngờ là /quick lại phản hồi ngay lập tức sau khi gọi /bad_async!

Tại sao?

Khi bạn dùng def, FastAPI hiểu rằng đây là một tác vụ đồng bộ → nó không chạy trong event loop chính, mà sẽ được đưa sang một thread phụ bằng ThreadPoolExecutor (có sẵn trong FastAPI/Uvicorn).

📚 Python Docs – ThreadPoolExecutor

Điều đó có nghĩa là:

  • time.sleep(5) chạy trong thread phụ, không ảnh hưởng đến event loop.
  • /quick vẫn được event loop xử lý bình thường.

4. Khi một async task nhường event loop, nó được xử lý ở đâu?

không được xử lý ở đâu cả trong lúc chờ đợi. Chính là:

Task đó bị tạm dừng, và event loop đi làm việc khác.

Sau khi việc chờ đợi (chẳng hạn await asyncio.sleep(5)) hoàn thành → event loop đánh thức lại task đó để tiếp tục.

📚 Real Python – Async IO in Python: A Complete Walkthrough


5. Còn aiofileshttpx thì sao?

Cũng tương tự, khi bạn làm:

async with aiofiles.open("data.txt", mode="r") as f: contents = await f.read() response = await httpx.get("https://example.com")

Đây là những tác vụ I/O bất đồng bộ → khi await, event loop sẽ tạm dừng task hiện tại và đi xử lý tác vụ khác trong khi đợi tác vụ I/O này hoàn tất.

Vậy ai sẽ "theo dõi" để báo lại cho event loop biết khi nào tác vụ đã xong?

Câu trả lời là:
📡 OS Kernel + Epoll/IOCP + lib như uvloop (hoặc mặc định asyncio loop).

  • Ở mức thấp, Python sử dụng selectors (trên Linux là epoll, trên Windows là IOCP) để "đăng ký" các socket hoặc file descriptor và chờ sự kiện I/O.
  • Khi một socket/file đã sẵn sàng để đọc/ghi, hệ điều hành sẽ "báo hiệu" lại cho event loop.
  • asyncio hoặc uvloop sẽ nhận thông báo này, và đưa task đang đợi đó quay lại vào hàng đợi để tiếp tục chạy.

📚 httpx Documentation – Async Support
📚 aiofiles GitHub Repository
📚 uvloop GitHub


6. Tổng kết

Tình huống Có nên dùng async không? Cần tránh gì?
Gọi đến API bất đồng bộ (httpx) ✅ Có ❌ Không dùng thư viện sync
Đọc ghi file (aiofiles) ✅ Có ❌ Không dùng open/read thường
Xử lý nặng CPU ❌ Không ✅ Nên dùng thread/process pool
Dùng time.sleep() ❌ Không ✅ Thay bằng await asyncio.sleep()

📚 Tài liệu tham khảo tổng hợp


Hy vọng bài viết này giúp bạn hiểu rõ hơn về async/await và event loop trong Python/FastAPI. Chúc bạn code hiệu quả hơn và tránh được những bug khó chịu do block event loop!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Lập Trình Hướng Đối Tượng trong Python

Chào các bạn Trong bài này, bạn sẽ tìm hiểu về Lập trình hướng đối tượng (OOP) bằng Python và khái niệm cơ bản của nó và một số các ví dụ. Các bạn cùng tìm hiểu trong bài viết của mình nhé.

0 0 69

- vừa được xem lúc

Lớp trong Python

. Hôm ni, mình học tiếp về bạn “Lớp(class) trong python”, bài blog tiếp theo nằm trong series “Khám phá Đại Bản Doanh Python”(nội dung trong bài series này từ chủ yếu mình lấy từ python.org rồi viết lại hoặc dịch lại theo ngôn ngữ của mình).

0 0 53

- vừa được xem lúc

Tìm hiểu về thư viện Numpy trong Python(Phần 3)

Trong bài viết trước tôi đã giới thiệu cho bạn về NumPy, tìm hiểu về Mảng trong NumPy. Trong bài viết này chúng ta sẽ tiếp tục tìm hiểu về các kiểu dữ liệu khác trong NumPy.

0 0 156

- vừa được xem lúc

Hướng dẫn cài đặt Anaconda trên Ubuntu

Anaconda là một nền tảng mã nguồn mở về Data Science và Machine Learning trên Python thông dụng nhất hiện nay, Anaconda có vai trò đơn giản hóa việc triển khai và quản lí các gói cài đặt khi làm việc với Python. Anaconda được cài đặt dễ dàng trên 3 nền tảng hệ điều hành thông dụng hiện nay là Ubuntu

0 0 59

- vừa được xem lúc

Tùy chỉnh Exceptions trong Python

Chào các bạn trong bài viết này, mình sẽ giới thiệu với các bạn về cách tùy chỉnh các Exceptions trong Python.Mình sẽ giải thích cho các bạn hiểu và cách xử dụng chúng.

0 0 54

- vừa được xem lúc

Không gian tên(namspace) và phạm vi(scope) trong Python

. Khi mình ngồi học và dịch bài "Class trong Python" cho sê-ri "Khám Phá Đại Bản Doanh Python", mình đã đụng hai bạn này, và các bạn thật là trừu tượng và khó gặm. Thế là mình tìm kiếm và viết bài này để hiểu rõ hơn về hai bạn ấy, hi vọng bạn đọc thêm để hiểu về Python nhé.

0 0 66