1、引言
asyncio 是 Python 標準庫中的一個庫,提供了對異步 I/O 、事件循環、協程和任務等異步編程模型的支持。
asyncio 文檔
2、進程、線程、協程
-
線程
線程是操作系統調度的基本單位,同一個進程中的多個線程共享相同的內存空間。線程之間的切換由操作系統內核負責。
特點:共享同一資源空間,切換時有開銷,但比進程小,適合 I/O 密集型任務,需要管理資源競爭問題。
-
進程
進程是操作系統資源分配的基本單位,每個進程有獨立的內存空間,進程之間不能共享內存,需要通過進程間通信(IPC)。
特點:任務完全獨立,互不干擾,各自有自己的資源,切換時開銷較大,適合 CPU 密集型任務。
-
協程
協程是由程序自身調度的函數,可以在執行過程中暫停和恢復,協程的切換由程序自身完成,而不是依賴操作系統。
特點:單線程內管理多任務,沒有線程切換的開銷,適合 I/O 密集型任務,需要程序自己管理任務的切換。
3 、asyncio 的基本使用
3.1 異步函數 和 await
異步函數使用 async def 聲明,await 關鍵字用于等待一個 異步操作完成。
代碼案例
import asyncioasync def hello():print("Hello")await asyncio.sleep(2)print("World")asyncio.run(hello())
注意:
- async 聲明后,不能直接 say_hello 運行函數
- 現在運行還是會 等待 1s 后執行 print(“World”)
- 協成本質上是事件循環。不是說用了 async await 就會成異步,是需要程序員自己定義任務有哪些協程的。
3.2 任務(Tasks)
任務用于調度和管理協程的執行。
代碼示例
import asyncioasync def greet(name):print(f"Hello, {name}")await asyncio.sleep(2)print(f"GoodBye: {name}")async def main():task1 = asyncio.create_task(greet("Tom"))task2 = asyncio.create_task(greet("Jerry"))await task1await task2asyncio.run(main())"""
輸出:
Hello, Tom
Hello, Jerry
GoodBye: Tom
GoodBye: Jerry
"""
4、本質
4.1 協程
協程是可以暫停和恢復的函數。與傳統的函數不同,協程可以在執行過程中暫停,以便其他協程可以運行。Python 使用 async def 聲明協程函數,使用 await 暫停協程的執行。
4.2 事件循環
事件循環是 asyncio 的核心,用于調度 和執行協程。事件循環負責處理異步函數、I/O 事件、定時器等。
4.3 任務 和 Future
任務是協程的高級抽象,用于調度協程的執行。Future 是表示異步操作結果的低級抽象,可以與任務一起使用。
5、高級使用
5.1 混合同步與異步IO
演示如何在異步環境中調用同步函數。
import asyncio# 同步函數
def sync_function():print("執行同步函數")# 異步函數
async def async_function():print("開始執行異步函數")await asyncio.sleep(2) # 模擬異步操作print("異步函數執行完成")# 在異步環境中調用同步函數
async def main():loop = asyncio.get_event_loop()await loop.run_in_executor(None, sync_function)await async_function()asyncio.run(main())"""
輸出
執行同步函數
開始執行異步函數
異步函數執行完成
"""
5.2 異步 I/O 中高級處理
import asyncioasync def my_async_function():try:await asyncio.wait_for(asyncio.sleep(5), timeout=3)except asyncio.TimeoutError:print("異步操作超時")asyncio.run(my_async_function())
5.3 異步I/O 中并發限制
有時候,為了避免資源耗盡,需要限制并發任務的數量。Asyncio提供了Semaphore來限制并發量。
asyncio.gather 是 Python 的 asyncio 模塊中的一個函數,用于并發運行多個異步任務并收集它們的結果。它允許你將多個協程(或可等待對象)打包在一起,并并發地執行它們。
import asyncioasync def limited_task(sem, num):async with sem:print(f"開始執行任務 {num}")await asyncio.sleep(2)print(f"任務 {num} 執行完成")async def main():sem = asyncio.Semaphore(5)tasks = [limited_task(sem, i) for i in range(10)]await asyncio.gather(*tasks)asyncio.run(main())