為什么在FastAPI中,ws.send_text("1")會先于load_dataset("beans")執(zhí)行?

為什么在FastAPI中,ws.send_text("1")會先于load_dataset("beans")執(zhí)行?

fastapi異步編程與await關(guān)鍵字:ws.send_text()和load_dataset()的執(zhí)行順序

本文探討在FastAPI框架中使用async/await進行異步編程時,ws.send_text()和load_dataset()函數(shù)的執(zhí)行順序問題。 之前的代碼示例中,存在一個誤解:ws.send_text(“1”)似乎需要等待load_dataset(“beans”)完成才能執(zhí)行。實際上并非如此。

關(guān)鍵在于理解await關(guān)鍵字的作用和load_dataset()函數(shù)的特性。 await 僅用于等待異步操作完成。ws.send_text()是一個異步操作,因此await ws.send_text(“1”)會等待消息發(fā)送完成。然而,load_dataset(“beans”)是一個同步阻塞操作,它會阻塞當(dāng)前協(xié)程直到數(shù)據(jù)集加載完成。

代碼執(zhí)行流程分析:

  1. await ws.accept(): 等待websocket連接建立。
  2. await ws.send_text(“1”): 異步發(fā)送消息”1″,此操作完成后繼續(xù)執(zhí)行。
  3. dataset = load_dataset(“beans”): 同步阻塞操作開始,程序在此處暫停,直到load_dataset(“beans”)從遠程下載并加載數(shù)據(jù)集完成。
  4. await ws.send_text(“2”): 異步發(fā)送消息”2″,同樣需要等待發(fā)送完成。

實驗驗證與結(jié)果解讀:

實驗結(jié)果清晰地表明,瀏覽器端先接收到”1″,然后才是”2″, 這與load_dataset(“beans”)的阻塞特性相符。 雖然ws.send_text(“1”)先執(zhí)行,但load_dataset(“beans”)的阻塞導(dǎo)致”2″的發(fā)送被延遲到數(shù)據(jù)集加載完成之后。

改進代碼以實現(xiàn)并發(fā):

如果需要load_dataset(“beans”)與ws.send_text(“1”)并發(fā)執(zhí)行,需要將load_dataset(“beans”)改造成異步操作。這通常需要使用異步IO庫,例如aiohttp來下載數(shù)據(jù)。 以下是一個改進后的示例(假設(shè)已使用aiohttp并實現(xiàn)了一個異步的load_dataset_async函數(shù)):

import asyncio from datetime import datetime  from datasets import load_dataset from fastapi import FastAPI, WebSocket from fastapi.responses import HTMLResponse  app = FastAPI()  # ... (HTML code remains the same) ...  @app.websocket("/ws") async def h(ws: WebSocket):     await ws.accept()     task = asyncio.create_task(load_dataset_async("beans")) # Asynchronously load dataset     await ws.send_text(f"1: {datetime.now()}")     dataset = await task # Await the dataset loading task     print(f"time: {datetime.now()} => dataset: {dataset}")     await ws.send_text(f"2: {datetime.now()}")     # ... (rest of the code remains the same) ... 

通過asyncio.create_task()創(chuàng)建異步任務(wù),load_dataset_async(“beans”)可以在后臺并發(fā)執(zhí)行,而不會阻塞主協(xié)程。

總結(jié): 原代碼中ws.send_text(“1”)先執(zhí)行,但load_dataset(“beans”)的同步阻塞特性決定了后續(xù)操作的執(zhí)行順序。 要實現(xiàn)并發(fā),必須將數(shù)據(jù)加載操作異步化。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊6 分享