我正在使用帶有 WebSockets 的 FastAPI 將 SVG“推送”到客戶端。問題是:如果迭代連續運行,它們會阻塞異步事件回圈,因此套接字無法監聽其他訊息。
將回圈作為后臺任務運行是不合適的,因為每次迭代都會占用大量 CPU,并且必須將資料回傳給客戶端。
是否有不同的方法,或者我需要從客戶端觸發每個步驟?我認為多處理可以作業,但不確定這將如何與等待 websocket.send_text() 之類的異步代碼一起作業。
我的第一個 S/O 問題,感謝您的幫助!
@app.websocket("/ws")
async def read_websocket(websocket: WebSocket) -> None:
await websocket.accept()
while True:
data = await websocket.receive_text()
async def run_continuous_iterations():
#needed to run the steps until the user sends "stop"
while True:
svg_string = get_step_data()
await websocket.send_text(svg_string)
if data == "status":
await run_continuous_iterations()
#this code can't run if the event loop is blocked by run_continuous_iterations
if data == "stop":
is_running = False
print("Stopping process")
uj5u.com熱心網友回復:
“...每次迭代都占用大量 CPU,并且必須將資料回傳給客戶端”。
如本答案中所述,“協程僅在明確請求暫停時才暫停其執行”,例如,如果有await對操作的呼叫,例如此處I/O-bound描述的操作。但是,這不適用于操作,例如此處提到的操作。因此,操作,即使它們在函式中宣告并使用 using 呼叫,也會阻塞事件回圈;因此,任何其他請求都將被阻止。CPU-boundCPU-boundasync defawait
此外,從您提供的代碼片段中,您似乎希望將資料發送回客戶端,同時收聽新訊息(以檢查客戶端是否發送“停止”訊息以停止程序)。因此,await完成一個操作不是要走的路,而是啟動一個執行緒/行程來執行該任務。下面的解決方案。
使用asyncio'srun_in_executor:
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
is_running = True
await websocket.accept()
try:
while True:
data = await websocket.receive_text()
async def run_continuous_iterations():
while is_running:
svg_string = get_step_data()
await websocket.send_text(svg_string)
if data == "status":
is_running = True
loop = asyncio.get_running_loop()
loop.run_in_executor(None, lambda: asyncio.run(run_continuous_iterations()))
if data == "stop":
is_running = False
print("Stopping process")
except WebSocketDisconnect:
is_running = False
print("Client disconnected")
使用threading'sThread:
#... rest of the code is the same as above
if data == "status":
is_running = True
thread = threading.Thread(target=lambda: asyncio.run(run_continuous_iterations()))
thread.start()
#... rest of the code is the same as above
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/457400.html
