async/await本質上通過協程和事件循環實現異步編程,提升i/o密集型任務效率。1. async def定義協程函數,調用時返回協程對象而非立即執行;2. await用于等待另一個可等待對象(如協程、任務)完成,在此期間當前協程掛起,控制權交還事件循環;3. 事件循環負責調度所有協程與任務,通過asyncio.run啟動程序并管理其生命周期;4. 并發運行多個協程可通過asyncio.gather()或create_task()將協程包裝為任務并發執行;5. 底層基于生成器與狀態機機制維護協程執行狀態;6. 使用時需注意:不能混用同步異步代碼,避免阻塞操作(如time.sleep),依賴支持異步的第三方庫。
在python中使用async/await語法進行異步編程,其實本質上是通過協程(coroutine)機制來實現的。它并不是真正意義上的“并發”執行多個任務,而是通過事件循環(Event loop)調度協程,在合適的時機切換執行流,從而達到高效處理I/O密集型任務的目的。
async/await 是怎么工作的?
當你在函數前加上 async def,Python就會把這個函數變成一個協程函數。調用這個函數并不會立即執行它,而是返回一個協程對象(coroutine Object)。要真正運行這個協程,你需要把它交給事件循環去調度執行。
而 await 的作用就是在這個協程內部等待另一個協程的結果。當遇到 await 時,當前協程會暫停執行,并把控制權交還給事件循環,讓其他協程有機會運行。
舉個簡單的例子:
立即學習“Python免費學習筆記(深入)”;
async def say_hello(): print("Hello") await asyncio.sleep(1) print("World") asyncio.run(say_hello())
這段代碼中,say_hello() 是一個協程函數。當它執行到 await asyncio.sleep(1) 時,當前協程會被掛起,事件循環可以去做別的事情(比如運行其他協程),等1秒后時間到了再回來繼續執行。
事件循環:異步程序的核心
所有基于 async/await 的異步操作都依賴于一個核心組件——事件循環(Event Loop)。你可以把它理解為一個調度器,負責管理所有的協程、任務和回調。
Python中的標準庫 asyncio 提供了事件循環的實現。從 Python 3.7 開始,推薦使用 asyncio.run() 來啟動一個異步程序,它會自動創建并關閉事件循環。
如果你需要同時運行多個協程,可以用 asyncio.gather() 或者 asyncio.create_task() 把它們包裝成任務(Task),然后一起交給事件循環:
-
使用 asyncio.gather():
async def main(): await asyncio.gather(say_hello(), say_hello()) asyncio.run(main())
-
使用 create_task():
async def main(): task1 = asyncio.create_task(say_hello()) task2 = asyncio.create_task(say_hello()) await task1 await task2 asyncio.run(main())
這兩個方法都能讓你的協程并發運行(注意不是并行),適合用來處理網絡請求、文件讀寫這類耗時但不占用CPU的操作。
底層原理:生成器與狀態機的結合
雖然我們看到的是簡潔的 async/await 語法,但其實在底層,Python是用生成器(generator)和狀態機的方式來實現協程的。
- async def 函數最終會被編譯成一個返回協程對象的函數。
- 協程對象內部維護了自己的執行狀態,每次被調度時都會從上次暫停的地方繼續執行。
- 每次遇到 await,Python都會檢查后面的對象是否是一個“可等待對象”(awaitable),比如另一個協程、任務或者Future。
- 如果是,當前協程就掛起自己,把控制權交給事件循環,直到被再次喚醒。
這背后其實是基于一種叫 promise/Future 的模型,配合事件循環實現了非阻塞的協作式多任務。
實際使用中要注意的問題
-
不能隨便混用同步和異步代碼
如果你在普通函數里直接調用協程函數,它不會執行,只會返回一個協程對象。一定要通過事件循環或 await 去驅動它運行。 -
阻塞操作會影響性能
異步的優勢在于利用空閑時間做其他事。如果你在協程中用了像 time.sleep() 這樣的阻塞操作,整個事件循環都會被卡住。應該用 await asyncio.sleep() 替代。 -
第三方庫支持很重要
要想充分發揮異步能力,你使用的庫也要支持異步方式,比如 aiohttp 替代 requests,asyncpg 替代 psycopg2 等。
基本上就這些。掌握好這些概念之后,你會發現 async/await 并不神秘,只是換了一種方式去組織你的邏輯,讓程序更高效地處理那些等待外部資源的任務。