[英]Sync & Async Python FastAPI scripts on Google App Engine
我嘗試在本地運行以下 py 文件script.py
:
from fastapi import FastAPI
import asyncio
import time
app = FastAPI()
@app.get('/async/')
async def func(text: str):
await asyncio.sleep(5)
return {'text': text}
@app.get('/sync/')
async def func(text: str):
time.sleep(5)
return {'text': text}
使用uvicorn script:app --reload
向同步端點http://127.0.0.1:8000/sync/?text=test
發出 10 個並發請求時,每個調用需要 5 秒並阻塞下一個,總時間為 50 秒
當向異步端點http://127.0.0.1:8000/async/?text=test
發出 10 個並發請求時,每個調用需要 5 秒,總時間也是 5 秒,因為它是非阻塞的。
我嘗試使用entrypoint: gunicorn -w 4 -k uvicorn.workers.UvicornWorker script:app
並進行了相同的測試而不是本地測試,並得到以下結果:
當向同步端點發出 10 個並發請求時,總時間為 12 秒,所有 10 個請求都在同一個實例上執行。 (1000 個並發請求在 20 多個實例上花費了 60 秒)
並且向異步端點發出 10 個並發請求時,總時間為 5 秒,所有 10 個請求都在同一個實例上執行。 (1000 個並發請求在 20 多個實例上花費了 30 秒)
為什么在 GAE 上,10 個並發請求的同步代碼需要 12 秒而不是 50 秒?
我怎樣才能在 GAE 上同時為同步端點運行所有 10 個請求,以在 5 秒內將它們全部獲取?
在您的 gunicorn 命令中,您指定了選項-w 4
,這意味着生成了 4 個工作進程( https://docs.gunicorn.org/en/stable/settings.html#worker-processes )。
即使在阻塞同步代碼的情況下,它也是一種啟用並發的常用方法。 您的 10 個請求被分配給工作人員(10 個請求 * 5 秒 / 4 個工作人員 = 12.5 秒)。
如果你像這樣運行它:
gunicorn -w 1 -k uvicorn.workers.UvicornWorker script:app
你會經歷 50 秒的等待。
但仍然強烈建議產生幾個工人。
現在對於同步部分,這里有一個關於 FastAPI 的有趣技術細節。 如果您將路由或依賴項定義為async
,它將在主進程中運行,無論您是否在內部運行阻塞代碼。
這就是您的/sync
端點阻塞的原因。
但是,如果將其定義為標准非異步 function,FastAPI 將在線程池中運行它以避免阻塞主進程。
文檔: https://fastapi.tiangolo.com/async/?h=technical#path-operation-functions
如果您像這樣編寫/sync
端點:
@app.get('/sync/')
def func(text: str): # Just removed the async keyword
time.sleep(5)
return {'text': text}
您會注意到端點不再阻塞主進程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.