python異步編程:函數執行順序詳解
在使用Python進行異步編程,特別是結合fastapi和websocket時,理解函數執行順序至關重要。本文分析一個常見誤解:ws.send_text(“1”) 為什么看起來需要等待load_dataset(“beans”)完成才能執行?
代碼示例及誤解:
以下代碼片段演示了這個問題:
from fastapi import FastAPI, WebSocket from datasets import load_dataset from datetime import datetime app = FastAPI() @app.websocket("/ws") async def h(ws: WebSocket): await ws.accept() await ws.send_text(f"1: {datetime.now()}") # 似乎等待load_dataset完成? dataset = load_dataset("beans") await ws.send_text(f"2: {datetime.now()}")
很多人誤以為ws.send_text(“1”)必須等待load_dataset(“beans”)加載完成后才會執行。
立即學習“Python免費學習筆記(深入)”;
真相與實驗:
為了驗證,我們加入時間戳,并添加一個簡單的html頁面用于接收WebSocket消息:
<!DOCTYPE html> <html> <head> <title>Chat</title> <h1>WebSocket Chat</h1> </head> <body> <ul id="messages"></ul> <form id="sendMessageForm" onsubmit="sendMessage(event)"> <input type="text" id="messageText"> <button type="submit">Send</button> </form> <script> var ws = new WebSocket("ws://localhost:8081/ws"); ws.onmessage = function(event) { var messages = document.getElementById('messages') var message = document.createElement('li') var content = document.createTextNode(event.data) message.appendChild(content) messages.appendChild(message) }; function sendMessage(event) { var input = document.getElementById("messageText") ws.send(input.value) input.value = '' event.preventDefault() } </script> </body> </html>
運行后,你會發現瀏覽器首先接收到”1: [時間戳]”,服務器日志隨后顯示load_dataset(“beans”)正在執行。這證明ws.send_text(“1”)的執行并不依賴于load_dataset(“beans”)的完成。
原因分析:
await ws.send_text(“1”)是異步操作,它將消息發送到WebSocket連接后立即返回,不會阻塞后續代碼的執行。load_dataset(“beans”)是一個耗時操作,但它也是異步執行的。 雖然load_dataset(“beans”)執行時間較長,但它不會阻塞ws.send_text(“1”)以及后續的ws.send_text(“2”),只是ws.send_text(“2”)的執行時間會被延遲。
因此,ws.send_text(“1”)在load_dataset(“beans”)之前發送,但由于load_dataset(“beans”)的耗時特性,”2: [時間戳]”的發送會被延遲。 這解釋了為什么瀏覽器先看到”1″,而服務器日志顯示數據加載仍在進行中。