Async View và ASGI trong Django 2026: Hiệu năng và câu hỏi phỏng vấn
Phân tích chuyên sâu về async view và ASGI trong Django 2026: cơ chế hoạt động bên dưới, server nên triển khai, async ORM cùng cái bẫy SynchronousOnlyOperation, kèm theo các câu hỏi phỏng vấn.

Async view trong Django cho phép một worker duy nhất xử lý hàng trăm request I/O-bound đồng thời mà không cần cấp riêng một thread cho mỗi kết nối, nhưng chỉ khi toàn bộ luồng code giữ được tính bất đồng bộ từ view xuống tới từng lệnh gọi mạng. Kể từ khi Django 3.1 giới thiệu view async def và Django 4.1 bổ sung giao diện async ORM, framework này đã trở thành một nền tảng ASGI đáng tin cậy, tuy vậy phần lớn các bản triển khai production vẫn chạy dưới WSGI và bỏ ngỏ khả năng xử lý đồng thời đó. Bài phân tích này giải thích cách async view vận hành dưới ASGI, những server nên chạy trong năm 2026, các cái bẫy của ORM khiến SynchronousOnlyOperation được ném ra, và những câu hỏi phỏng vấn phân biệt kỹ sư đã từng đưa async Django lên production với người chỉ mới đọc về nó.
Async view mang lại lợi ích khi một request dành phần lớn thời gian chờ đợi I/O nằm ngoài tầm kiểm soát: các HTTP API bên thứ ba, các dịch vụ downstream chậm, hoặc các response streaming tồn tại lâu. Với công việc CPU-bound hay các truy vấn cơ sở dữ liệu cục bộ nhanh, một view đồng bộ được hỗ trợ bởi nhiều Gunicorn worker hơn thường nhanh hơn và dễ suy luận hơn nhiều.
Cách async view của Django hoạt động dưới ASGI
WSGI về bản chất là đồng bộ: mỗi request đang xử lý chiếm giữ một thread hoặc process của worker từ đầu đến cuối, nên 50 request chậm cần tới 50 worker. ASGI thay thế mô hình đó bằng một event loop đan xen nhiều request trên cùng một worker, tạm ngưng một coroutine mỗi khi nó await I/O và tiếp tục khi dữ liệu về tới. Tài liệu async chính thức của Django mô tả hai adapter khiến sự cùng tồn tại này khả thi: dưới ASGI, Django chạy view async def một cách nguyên bản trên loop và đẩy các view đồng bộ vào một threadpool bằng sync_to_async; dưới WSGI, nó bọc các async view trong async_to_sync và chạy tới khi hoàn tất, loại bỏ mọi lợi ích về xử lý đồng thời.
Hệ quả thực tế rất rõ ràng: một view async def triển khai trên server WSGI hành xử như một view đồng bộ nhưng chậm hơn. Khả năng xử lý đồng thời chỉ thành hiện thực trên server ASGI. Một async view tối giản gọi tới một API bên ngoài trông gần như giống hệt phiên bản đồng bộ tương ứng, với khác biệt tập trung ở await.
# views.py
import httpx
from django.http import JsonResponse
async def dashboard(request):
# Dưới ASGI, coroutine này chạy trên event loop, nên worker được
# rảnh để phục vụ các request khác trong khi httpx await vòng trao đổi mạng.
async with httpx.AsyncClient(timeout=5.0) as client:
response = await client.get("https://api.example.com/metrics")
return JsonResponse(response.json())Lợi ích ở đây không phải là một request đơn lẻ hoàn thành nhanh hơn; nó vẫn tốn đúng khoảng thời gian thực như nhau. Lợi ích là worker không bị chặn trong lúc await, nhờ đó throughput dưới tải đồng thời tăng lên trong khi số lượng process vẫn giữ nguyên.
Cùng mô hình đó mở khóa những kiểu response vốn khó thực hiện dưới WSGI. Kể từ Django 4.2, StreamingHttpResponse chấp nhận một async generator, nên một view có thể yield từng chunk ngay khi nguồn upstream tạo ra chúng, điều này phù hợp với Server-Sent Events và các luồng token LLM được proxy nơi kết nối giữ mở trong nhiều giây. Các giao thức hai chiều bền vững như WebSocket vẫn đi qua Django Channels thay vì các view HTTP thuần, nhưng cả hai đều dựa trên cùng một nền tảng ASGI, nên một dự án áp dụng async view đã trả trước chi phí hạ tầng cho các tính năng real-time về sau.
Chọn server ASGI cho Django trong năm 2026
Django đóng gói sẵn một đối tượng ứng dụng ASGI trong asgi.py, nhưng nó không tự chạy; cần một server ASGI chuyên dụng để điều khiển event loop. Đặc tả ASGI định nghĩa giao diện mà mọi server trong số này đều hiện thực, đó là lý do chúng có thể thay thế cho nhau ở mức giao thức và chủ yếu khác biệt về hiệu năng cùng phạm vi giao thức hỗ trợ.
| Server | Ngôn ngữ hiện thực | Phù hợp nhất | |--------|----------------|----------| | Uvicorn | Python (uvloop) | ASGI tổng quát, HTTP/1.1, lựa chọn mặc định phổ biến | | Daphne | Python | Django Channels, WebSocket, HTTP/2 | | Granian | Rust | Throughput thô cao nhất, HTTP/1 và HTTP/2 | | Hypercorn | Python | HTTP/2 và HTTP/3 (QUIC) |
Với phần lớn các bản triển khai năm 2026, Uvicorn chạy dưới dạng một worker class của Gunicorn vẫn là lựa chọn đáng tin cậy: Gunicorn giám sát vòng đời process, khởi động lại các worker bị crash và xử lý tín hiệu, trong khi Uvicorn điều khiển event loop bên trong mỗi worker. Một chi tiết di chuyển thường gây vướng khi nâng cấp: các worker class của Gunicorn đã được tách khỏi lõi Uvicorn thành một package uvicorn-worker riêng kể từ Uvicorn 0.30, nên đường dẫn import đã thay đổi.
# Cài package worker trước: pip install uvicorn-worker
gunicorn myproject.asgi:application \
--workers 4 \
--worker-class uvicorn_worker.UvicornWorker \
--bind 0.0.0.0:8000Các nhóm theo đuổi throughput tối đa ngày càng chọn Granian, một server viết bằng Rust loại bỏ chi phí phân tích HTTP ở phía Python. Dù chọn cách nào, chính câu chuyện triển khai là lý do async chỉ xuất hiện trong production khi được cấu hình một cách có chủ đích; phần thiết lập riêng cho ASGI phản ánh đúng sự cẩn trọng vận hành được trình bày trong module câu hỏi phỏng vấn về triển khai Django.
Async ORM và cái bẫy SynchronousOnlyOperation
Django 4.1 đã bổ sung các phương thức truy vấn bất đồng bộ khắp ORM: aget, acreate, asave, adelete, acount, aexists, aaggregate, và duyệt bằng async for. Chúng cung cấp một bề mặt thân thiện với async, nhưng một lưu ý quan trọng vẫn còn nguyên tới năm 2026: tầng cơ sở dữ liệu bên dưới không thực sự bất đồng bộ nguyên bản. Ngay cả với psycopg3, Django vẫn thực thi truy vấn trong một threadpool và phơi bày chúng qua các lớp bọc async, nên async ORM cải thiện trải nghiệm sử dụng và tránh chặn loop mà không mang lại I/O cơ sở dữ liệu bất đồng bộ đúng nghĩa xuyên suốt.
Kiểu lỗi phổ biến nhất là gọi trực tiếp một phương thức ORM đồng bộ ngay bên trong một async view. Django phát hiện ngữ cảnh async và từ chối, ném ra SynchronousOnlyOperation để ngăn một lệnh gọi gây chặn đóng băng event loop đối với mọi request khác đang dùng chung worker đó.
Ngoại lệ này là một rào chắn bảo vệ, không phải một lỗi. Việc dùng tới DJANGO_ALLOW_ASYNC_UNSAFE=true để làm nó im lặng chính là tái tạo lại đúng hành vi gây chặn mà async vốn được sinh ra để loại bỏ. Cách khắc phục đúng đắn là dùng một phương thức async ORM (aget thay cho get) hoặc bọc tường minh bằng sync_to_async quanh đoạn code không có phiên bản async tương ứng.
Async view trở nên rõ ràng, dễ đọc khi các phương thức truy vấn async thay thế những phiên bản đồng bộ song sinh của chúng. Mẫu code dưới đây đếm số bản ghi và truyền mười bản ghi đầu tiên mà không bao giờ rời khỏi event loop.
# views.py
from django.http import JsonResponse
from .models import Article
async def latest_articles(request):
# acount() và việc duyệt bằng async là các lớp bọc an toàn với async quanh ORM.
count = await Article.objects.acount()
titles = []
async for article in Article.objects.order_by("-created_at")[:10]:
titles.append(article.title)
return JsonResponse({"count": count, "titles": titles})Một số đoạn code không có phiên bản async tương ứng: một SDK bên thứ ba chỉ cung cấp các lệnh gọi đồng bộ, hoặc một chuỗi duyệt ORM dày đặc không đáng để viết lại. Việc bọc nó trong sync_to_async từ thư viện asgiref chuyển phần việc đó sang một thread và giữ cho loop luôn phản hồi tốt. Tham số thread_sensitive=True là mặc định an toàn vì nó định tuyến mọi lệnh gọi được bọc tới cùng một thread executor dùng chung, bảo toàn kết nối cơ sở dữ liệu và trạng thái transaction vốn sẽ hỏng nếu các lệnh gọi bị phân tán ra những thread bất kỳ.
# views.py
from asgiref.sync import sync_to_async
from .services import build_report # một hàm đồng bộ
async def report_view(request):
# thread_sensitive=True giữ các lệnh gọi được bọc trên cùng một thread dùng chung,
# bảo toàn kết nối và trạng thái transaction khi vượt qua ranh giới.
report = await sync_to_async(build_report, thread_sensitive=True)(request.user.id)
return JsonResponse(report)Hiệu năng async trong Django: Khi xử lý đồng thời thắng thế
Hiệu năng async của Django là câu chuyện về chồng lấn I/O, không phải tốc độ thô. Lợi ích rõ ràng nhất đến từ việc trải rộng các lệnh gọi mạng độc lập bằng asyncio.gather: ba request bên ngoài, mỗi request 200ms, tốn khoảng 600ms nếu chạy tuần tự nhưng hoàn thành trong khoảng 200ms khi chạy đồng thời, bởi các lệnh await chồng lấn lên nhau trên cùng một loop.
# views.py
import asyncio
import httpx
from django.http import JsonResponse
async def aggregate(request):
async with httpx.AsyncClient(timeout=5.0) as client:
# Ba lệnh gọi độc lập chạy đồng thời thay vì lần lượt từng cái một.
weather, prices, news = await asyncio.gather(
client.get("https://api.example.com/weather"),
client.get("https://api.example.com/prices"),
client.get("https://api.example.com/news"),
)
return JsonResponse({
"weather": weather.json(),
"prices": prices.json(),
"news": news.json(),
})Trường hợp ngược lại cũng quan trọng không kém. Một view chỉ chạy một truy vấn cục bộ nhanh duy nhất chẳng thu được gì từ async và thường còn thiệt hại, bởi giờ đây mỗi request phải trả thêm chi phí lập lịch của event loop cộng thêm một bước nhảy qua threadpool để vào driver cơ sở dữ liệu đồng bộ. Async còn áp một khoản phí tinh vi hơn tại mỗi ranh giới sync/async: việc trộn lẫn middleware đồng bộ và bất đồng bộ buộc Django phải chuyển đổi giữa loop và một thread ở mỗi lần chuyển tiếp, và một request vượt qua ranh giới đó nhiều lần cho mỗi response sẽ tích lũy độ trễ thực sự. Giữ cho stack middleware đồng nhất là async, hoặc đồng nhất là sync, sẽ loại bỏ những lần chuyển đổi đó.
Quyết định rốt cuộc quy về hình dạng của khối lượng công việc chứ không phải sự ưa thích cú pháp hiện đại.
| Khối lượng công việc | Lựa chọn mặc định tốt hơn |
|----------|----------------|
| Nhiều lệnh gọi API bên ngoài chậm cho mỗi request | Async view với asyncio.gather |
| Streaming tồn tại lâu hoặc Server-Sent Events | Async view với một async generator |
| Một truy vấn cơ sở dữ liệu nhanh, ít dùng CPU | Sync view, nhiều Gunicorn worker hơn |
| Render hoặc tính toán CPU-bound | Sync view, đẩy sang một task queue |
Với những tác vụ thực sự chạy dài, async view hoàn toàn là công cụ sai; giữ một request mở để làm việc trong nhiều phút là lãng phí kết nối bất kể mô hình xử lý đồng thời nào. Phần việc đó thuộc về một background worker, một sự đánh đổi được phân tích trong bài hướng dẫn về tác vụ async với Celery trong Django.
Việc áp dụng nên đi theo đo lường thay vì trực giác. Cách trung thực để biện minh cho async là load-test đúng endpoint cụ thể bằng một công cụ như Locust hoặc k6 dưới mức đồng thời thực tế, so sánh một phiên bản đồng bộ trên N worker với một phiên bản async trên cùng phần cứng. Những endpoint bị chi phối bởi một lệnh gọi bên ngoài duy nhất có độ trễ cao cho thấy khoảng cách lớn nghiêng về phía async; những endpoint bị chi phối bởi các truy vấn nhanh lại thường cho thấy async chậm hơn đôi chút một khi tính đến bước nhảy qua threadpool. Việc profiling request trước cũng hé lộ liệu điểm nghẽn có thực sự là I/O hay không, bởi async chẳng làm được gì cho một view chậm vì các truy vấn thiếu index, một vấn đề được giải quyết trong bài hướng dẫn về tối ưu truy vấn ORM của Django.
Sẵn sàng chinh phục phỏng vấn Django?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Câu hỏi phỏng vấn về async trong Django năm 2026
Một buổi phỏng vấn về async trong Django dò xét xem ứng viên hiểu được mô hình hay chỉ đơn thuần nhận ra các từ khóa. Những câu hỏi dưới đây phản ánh điều mà các buổi phỏng vấn cấp senior thực sự đặt ra trong năm 2026, mỗi câu đi kèm câu trả lời mà một kỹ sư giàu kinh nghiệm sẽ đưa ra.
Điều gì thay đổi khi một async view chạy dưới WSGI thay vì ASGI? Dưới WSGI, Django bọc coroutine trong async_to_sync và chạy nó tới khi hoàn tất trên thread của request, nên nó hành xử như một view đồng bộ nhưng chậm hơn, không có chút lợi ích xử lý đồng thời nào. Chỉ một server ASGI chạy event loop mới cho phép worker phục vụ các request khác trong lúc await.
Vì sao Article.objects.get(pk=1) ném ra SynchronousOnlyOperation bên trong một async view? Lệnh gọi ORM đồng bộ sẽ chặn event loop, làm đình trệ mọi request khác trên worker đó. Django phát hiện ngữ cảnh async và từ chối. Cách khắc phục là dùng phương thức async await Article.objects.aget(pk=1), hoặc sync_to_async cho đoạn code không có phiên bản async tương ứng.
ORM async của Django có thực sự không gây chặn hay không? Không. Các phương thức async chỉ là những lớp bọc tiện dụng; các truy vấn bên dưới vẫn chạy trong một threadpool bởi các driver cơ sở dữ liệu chưa được tích hợp để thực thi async nguyên bản xuyên suốt. Lợi ích là giữ cho loop rảnh rỗi, chứ không phải I/O cơ sở dữ liệu song song ở mức driver.
Khi nào nên chọn async view thay vì một task queue như Celery? Async view phù hợp với việc xử lý đồng thời I/O trong phạm vi một request và phải hoàn tất trước khi trả response, chẳng hạn như tổng hợp nhiều API. Công việc kéo dài quá thời gian sống của request, cần retry, hoặc chạy trong nhiều phút thuộc về Celery hoặc background task của Django, bởi việc giữ một kết nối HTTP mở cho nó là lãng phí tài nguyên server.
Chi phí của việc trộn lẫn middleware sync và async là gì? Mỗi lần chuyển tiếp giữa một thành phần sync và một thành phần async buộc Django phải nhảy giữa event loop và một thread thông qua sync_to_async hoặc async_to_sync. Một request vượt qua ranh giới đó nhiều lần phải trả chi phí tích lũy, nên một stack middleware đồng nhất hoạt động tốt hơn một stack đan xen.
Kết luận
- Async view chỉ mang lại khả năng xử lý đồng thời trên một server ASGI; chính view đó dưới WSGI chạy đồng bộ thông qua
async_to_sync. - Triển khai Uvicorn qua package
uvicorn-workerdưới Gunicorn, hoặc Granian để đạt throughput tối đa, và xem việc thiết lập ASGI như một bước triển khai tường minh. - Dùng async view khi một request chờ đợi nhiều lệnh gọi I/O bên ngoài chậm; giữ các endpoint truy vấn nhanh và CPU-bound ở dạng đồng bộ với nhiều worker hơn.
- Dùng
aget,acreatevàasync forbên trong async view, và nhớ rằng ORM vẫn chạy truy vấn trong một threadpool chứ không phải async nguyên bản. - Xem
SynchronousOnlyOperationnhư một rào chắn bảo vệ: khắc phục bằng các phương thức async hoặcsync_to_async(thread_sensitive=True), đừng bao giờ vô hiệu hóa kiểm tra này. - Giữ stack middleware đồng nhất là sync hoặc async để tránh trả phí chuyển đổi thread mỗi lần vượt qua ranh giới.
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Thẻ
Chia sẻ
Bài viết liên quan

Django va Celery: Xu ly Tac vu Bat dong bo va Cau hoi Phong van 2026
Huong dan Django Celery day du voi ma code thuc te, task routing, lap lich Celery Beat, cau hinh production va cau hoi phong van ky thuat 2026.

Tìm Hiểu Sâu Về Serializer Django REST Framework: Validation, Nested và Tối Ưu N+1
Hướng dẫn toàn diện về DRF serializers: pipeline validation, nested serializers, xử lý quan hệ phức tạp và các kỹ thuật tối ưu để tránh vấn đề N+1 queries.

Django và PostgreSQL năm 2026: Đánh chỉ mục, tìm kiếm toàn văn và câu hỏi phỏng vấn
Hướng dẫn thực hành tối ưu Django với PostgreSQL: chỉ mục B-tree, một phần và bao phủ, tìm kiếm toàn văn với SearchVector và GIN, cùng các câu hỏi phỏng vấn 2026.