在 Python 中,為什么 ws.send_text("1") 必須等待 load_dataset("beans") 加載完畢后才執行?

在 Python 中,為什么 ws.send_text("1") 必須等待 load_dataset("beans") 加載完畢后才執行?

python 異步編程中 await 關鍵字的執行順序分析

本文探討 Python 異步編程中 await 關鍵字的執行順序,特別是結合 fastapiwebsocket 的場景。 一個常見的誤解是,await 之后的代碼會立即執行,而實際情況并非總是如此。

以下代碼示例演示了這個問題:

from fastapi import FastAPI, WebSocket from datasets import load_dataset  app = FastAPI()  @app.websocket("/") async def h(ws: WebSocket):     await ws.accept()     await ws.send_text("1")     dataset = load_dataset("beans")  # 阻塞操作     await ws.send_text("2")

直覺上,我們期望 “1” 先發送,然后加載數據集,最后發送 “2”。但實際上,”1″ 的發送會阻塞,直到 load_dataset(“beans”) 完成。這是因為 load_dataset(“beans”) 是一個同步(阻塞)函數,它會阻止異步函數的后續執行。

為了更清晰地觀察執行順序,我們修改代碼,加入時間戳:

立即學習Python免費學習筆記(深入)”;

from datetime import datetime from datasets import load_dataset from fastapi import FastAPI, WebSocket from fastapi.responses import HTMLResponse  app = FastAPI()  # ... (HTML 代碼保持不變) ...  @app.websocket("/ws") async def h(ws: WebSocket):     await ws.accept()     await ws.send_text(f"1: {datetime.now()}")     dataset = load_dataset("beans")     print(f"time: {datetime.now()} => dataset: {dataset}")     await ws.send_text(f"2: {datetime.now()}")     while True:         data = await ws.receive_text()         await ws.send_text(f"Message text was: {data}, datetime: {datetime.now()}")

運行修改后的代碼,你會發現 “1” 確實先發送到客戶端,瀏覽器接收到了 websocket 信息。這證明 ws.send_text(“1”) 先執行。然而,load_dataset(“beans”) 的阻塞特性導致了 “2” 的發送延遲。

結論

await 關鍵字只等待異步操作完成。如果 await 后面跟著的是同步函數,那么這個同步函數的執行會阻塞整個異步函數,直到同步函數執行完畢。 因此,在異步函數中,應盡量避免使用阻塞操作,或者使用異步替代方案來提高效率和響應速度。 在上述例子中,如果 load_dataset 有異步版本,則應優先使用。

以上就是在 Python 中,

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享