[英]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.