事件循環
事件循環 = 協調所有協程執行的中央調度器,它通過非阻塞機制,實現并發執行多個異步任務。
事件循環是 異步編程的核心機制,用一句話概括就是:
事件循環不斷檢查任務隊列,一旦某個異步任務完成,它就調用該任務的回調并繼續循環執行。
它的目標是:非阻塞地執行多個任務(如 I/O、網絡請求),避免因為等待某個任務而卡住整個程序。
概念 | 說明 |
---|---|
協程(coroutine) | 你寫的 async def 函數 |
任務(Task) | 協程包裝成可調度對象,由事件循環驅動執行 |
Future | 代表“未來某個時間點”的值;Task 是它的子類 |
async def xxx():↓
coroutine obj↓
Task.create↓
注冊到 event loop↓
loop.run_until_complete()↓
調度、掛起、恢復...
事件循環最大的優勢在于:可以在等待 I/O(如網絡、磁盤)時釋放 CPU 去執行其他任務。
- 并發網絡請求(aiohttp)
- 異步數據庫訪問(如 asyncpg)
- Web 框架(FastAPI、Sanic)
- 實時任務調度系統(如定時器、爬蟲)
asyncio
asyncio 是 Python 3.4 引入的標準庫,用于編寫協程式的異步代碼。它的核心包括:
- 事件循環(Event Loop)
- 協程(Coroutine)
- Task / Future 管理
- 異步 I/O 支持(網絡、文件、子進程等)
- 高級工具(如 asyncio.gather()、Queue、鎖等)
本質:asyncio 提供了一個異步框架,用于非阻塞的 I/O 編程。
uvloop
uvloop 是一個用 Cython 編寫的 高性能事件循環實現,替代默認的 asyncio 事件循環。它基于 libuv(Node.js 的底層庫),因此性能極佳。
特點:
- 全兼容 asyncio 接口
- 性能提升 2~4 倍(實際測試中)
- 安裝簡單,幾乎無縫切換
比較
uvloop 比默認 asyncio 更快,本質原因在于事件循環的底層實現完全不同:uvloop 用 C/Cython 構建并基于 libuv,而默認 asyncio 用純 Python 和 selectors 實現,性能存在數量級差異。
特性 | asyncio(默認事件循環) | uvloop(替代實現) |
---|---|---|
性能 | 中規中矩 | 高性能、近 C 語言速度 |
實現語言 | 純 Python + C | Cython + libuv |
使用方式 | 內置、開箱即用 | pip 安裝 + 手動設置 |
兼容性 | 官方標準 | 完全兼容 asyncio |
實現 | 吞吐量(req/s) | 延遲(ms) |
---|---|---|
asyncio | 5,000 req/s | 20ms |
uvloop | 15,000 req/s | 7ms |
使用場景 | 推薦使用 |
---|---|
CPU 密集型任務 | ? 不適合 asyncio(建議多線程或多進程) |
I/O 密集型任務(網絡、文件等) | ? 推薦 asyncio + uvloop |
高并發服務(Web、代理、網關等) | ? 強烈推薦 uvloop 提升吞吐和穩定性 |
?uvloop 是不支持 Windows 的!它是專為 Unix/Linux/macOS 優化的高性能事件循環。
- uvloop 是基于 libuv 實現的,而 libuv 的 Windows 支持不適合用作 Python 的事件循環替代。
- Windows 的 asyncio 默認使用的是 ProactorEventLoop(基于 IOCP),和 libuv 的模型完全不同。
使用 uvloop 來實現 高并發 部署:
CMD ["uvicorn", "web.main:app", "--host", "0.0.0.0", "--port", "8077", "--loop", "uvloop", "--http", "h11"]
維度 | asyncio**(默認事件循環)** | uvloop |
---|---|---|
實現語言 | Python + 少量 C | Cython + libuv(C語言) |
底層機制 | 使用 selectors(如 epoll/kqueue)做調度,Python 層調度任務和回調 | 直接使用高性能 libuv,類似 Node.js 的底層模型 |
調度邏輯 | Python 層事件循環和回調調度開銷較大 | C 層事件循環和回調分發更快,幾乎無 Python 層切換開銷 |
系統調用封裝 | Python 層對 socket/select 封裝 | C 層封裝系統調用,效率極高 |
GC 壓力 | 更多 Python 對象交互 | 減少 Python 調度邏輯,內存壓力更小 |
- 在 asyncio 中,事件循環會:
- 通過 selectors 監聽 socket 是否可讀
- 如果 socket 可讀,則通過 Python 層的回調觸發處理
- 執行用戶協程,繼續 await…
這個過程中:
👉 Python 層頻繁調用回調函數、切換上下文、管理 Future 狀態,調度開銷較大
但 uvloop 做了什么?
- 使用 C 寫的 libuv 做事件循環(本來就是 Node.js 的核心)
- 所有事件監聽、回調調度、超時處理等都在 C 層完成
- Python 只負責“最終執行協程”,調度工作都交給高性能 C 層完成
所以:
uvloop 省去了 Python 層大量的中間操作,減少了解釋器層面的性能瓶頸。
uvloop 主要提升在:
- I/O 調度速度
- 協程切換效率
- 回調調用效率
但對于 CPU 密集型任務(如復雜數據處理、機器學習),uvloop 并不會提升太多,應考慮多進程或線程池。
uvloop 比 asyncio 快的本質在于:它把事件循環和 I/O 調度從 Python 層搬到了高效的 C 層(libuv),最大限度減少了解釋器負擔。