Django - 異步處理(Asynchronous Processing)
在現代 Web 開發中,異步處理(Asynchronous Processing)變得越來越重要,特別是當應用需要高效處理大量請求或執行 I/O 密集型操作時。從 Django 3.1 開始,Django 開始支持異步視圖與中介軟體,使其能更好地處理異步操作。
課程目標
- 理解同步與異步的區別。
- 瞭解 Django 的異步支持,包括異步視圖和中介軟體。
- 學習如何實現異步任務,並與外部服務進行協作。
課程內容
1. 同步與異步的基礎知識
1.1 同步 (Synchronous)
- 同步請求處理是逐步執行的。
- 當執行一個阻塞操作(例如 I/O 操作)時,程序會停下來等待結果。
1.2 異步 (Asynchronous)
- 異步請求允許在執行阻塞操作時繼續處理其他請求。
- 提升性能,特別是在處理大量 I/O 操作時(例如 API 調用、讀寫文件等)。
2. Django 的異步支持
2.1 異步視圖
從 Django 3.1 開始,視圖可以聲明為異步函數:
1
2
3
4
5
6
from django.http import JsonResponse
import asyncio
async def async_view(request):
await asyncio.sleep(2) # 模擬耗時操作
return JsonResponse({"message": "This is an async view!"})
2.2 異步中介軟體
中介軟體也可以支持異步執行:
1
2
3
4
5
6
from django.utils.deprecation import MiddlewareMixin
class AsyncMiddleware(MiddlewareMixin):
async def __call__(self, request):
response = await super().__call__(request)
return response
3. 異步任務實現
3.1 使用異步 HTTP 請求
在異步視圖中,可以使用第三方庫如 httpx
發起非阻塞的 HTTP 請求:
1
2
3
4
5
6
7
import httpx
from django.http import JsonResponse
async def fetch_data_view(request):
async with httpx.AsyncClient() as client:
response = await client.get('https://jsonplaceholder.typicode.com/posts/1')
return JsonResponse(response.json())
3.2 與資料庫交互
Django 內建的 ORM 目前不支持異步操作,因此在異步視圖中仍然需要通過同步方式與資料庫交互。可以考慮將 ORM 操作移至線程池中執行:
1
2
3
4
5
6
7
8
9
from django.db import models
from asgiref.sync import sync_to_async
class Task(models.Model):
title = models.CharField(max_length=255)
async def async_db_view(request):
tasks = await sync_to_async(list)(Task.objects.all())
return JsonResponse({"tasks": [task.title for task in tasks]})
4. 實現異步任務隊列
使用 Celery 配合 Django,實現異步背景任務執行。
4.1 安裝 Celery
1
pip install celery[redis]
4.2 配置 Celery
在項目根目錄下創建 celery.py
:
1
2
3
4
5
6
7
8
9
10
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
在 __init__.py
中導入 Celery:
1
2
3
4
from __future__ import absolute_import, unicode_literals
# 這確保應用程序啟動時載入 Celery
from .celery import app as celery_app
__all__ = ('celery_app',)
4.3 定義異步任務
在 tasks/tasks.py
中:
1
2
3
4
5
from celery import shared_task
@shared_task
def add(x, y):
return x + y
4.4 調用異步任務
在視圖中調用 Celery 任務:
1
2
3
4
5
6
from django.http import JsonResponse
from .tasks import add
def trigger_task_view(request):
task = add.delay(3, 4) # 執行任務
return JsonResponse({"task_id": task.id, "status": "Task triggered!"})
5. 測試異步功能
5.1 測試異步視圖
使用 Django 的測試框架測試異步視圖:
1
2
3
4
5
6
7
8
9
from django.test import AsyncClient
import pytest
@pytest.mark.asyncio
async def test_async_view():
client = AsyncClient()
response = await client.get('/async/')
assert response.status_code == 200
assert response.json() == {"message": "This is an async view!"}
5.2 測試 Celery 任務
測試 Celery 任務可以使用 apply
直接執行:
1
2
3
4
5
from .tasks import add
def test_add_task():
result = add.apply((3, 4)) # 執行同步任務
assert result.result == 7
總結
- Django 的異步支持允許開發者編寫高性能的 Web 應用。
- Celery 是執行背景任務的強大工具,與 Django 緊密集成。
- 異步功能適合 I/O 密集型操作,但需要注意 ORM 的同步限制。
作業
- 使用 Django 和 Celery 實現一個定時任務,模擬每日數據統計。
- 編寫一個異步視圖,調用多個外部 API 並整合結果返回。
- 嘗試將 ORM 操作移至線程池中,實現與資料庫的非阻塞交互。
本文章以 CC BY 4.0 授權