我写了一个fastapi应用程序。现在我正在考虑部署它,但是我似乎遇到了奇怪的意外性能问题,这似乎取决于我使用的是uvicorn还是gunicorn。特别是,如果我使用gunicorn,所有代码(甚至是标准库纯python代码)似乎都会变慢。为了进行性能调试,我编写了一个小应用程序来演示这一点:
import asyncio, time
from fastapi import FastAPI, Path
from datetime import datetime
app = FastAPI()
@app.get("/delay/{delay1}/{delay2}")
async def get_delay(
delay1: float = Path(..., title="Nonblocking time taken to respond"),
delay2: float = Path(..., title="Blocking time taken to respond"),
):
total_start_time = datetime.now()
times = []
for i in range(100):
start_time = datetime.now()
await asyncio.sleep(delay1)
time.sleep(delay2)
times.append(str(datetime.now()-start_time))
return {"delays":[delay1,delay2],"total_time_taken":str(datetime.now()-total_start_time),"times":times}
使用以下各项运行fastapi appi:
gunicorn api.performance_test:app -b localhost:8001 -k uvicorn.workers.UvicornWorker --workers 1
get to http://localhost:8001/delay/0.0/0.0
的响应体始终类似于:
{
"delays": [
0.0,
0.0
],
"total_time_taken": "0:00:00.057946",
"times": [
"0:00:00.000323",
...smilar values omitted for brevity...
"0:00:00.000274"
]
}
但是,使用:
uvicorn api.performance_test:app --port 8001
我总是得到这样的时间安排
{
"delays": [
0.0,
0.0
],
"total_time_taken": "0:00:00.002630",
"times": [
"0:00:00.000037",
...snip...
"0:00:00.000020"
]
}
当我取消对await asyncio.sleep(delay1)
语句的注释时,这种差异变得更加明显
所以我想知道gunicorn/uvicorn对python/fastapi运行时做了什么,从而在代码执行速度上产生了10倍的差异
值得一提的是,我在OS X 11.2.3和intel I7处理器上使用Python 3.8.2执行了这些测试
这些是我的输出的相关部分
fastapi==0.65.1
gunicorn==20.1.0
uvicorn==0.13.4
我无法复制你的结果
我的环境: Windows 10上WSL2上的ubuntu
我的
pip freeze
输出的相关部分:我稍微修改了代码:
除了第一次加载网站,我对这两种方法的结果几乎相同
这两种方法的大多数时间都在
0:00:00.000530
和0:00:00.000620
之间第一次尝试每种方法需要更长的时间:大约
0:00:00.003000
。 然而,在我重新启动Windows并再次尝试这些测试后,我注意到在服务器启动后,我不再增加第一次请求的次数(我认为这要感谢重新启动后的大量空闲RAM)非首次运行的示例(3次尝试):
非首次运行带有注释的
await asyncio.sleep(delay1)
(3次尝试)的示例:我制作了一个Python脚本来更精确地测试这些时间:
结果:
带有注释的结果
await asyncio.sleep(delay1)
我还制作了上述脚本的另一个版本,每1个请求更改一次URL(它给出的次数稍高):
结果:
带有注释的结果
await asyncio.sleep(delay1)
这个答案应该可以帮助您更好地调试结果
我认为如果你分享更多关于你的操作系统/机器的细节,调查你的结果可能会有所帮助
另外,请重新启动计算机/服务器,这可能会产生影响
更新1:
我看到我使用了比问题{}中所述更新的版本。
我还使用旧版本
0.13.4
进行了测试,但结果类似,我仍然无法重现您的结果更新2:
我又运行了一些基准测试,发现了一些有趣的事情:
在requirements.txt中使用uvloop:
完整要求.txt:
结果:
在requirements.txt中没有uvloop:
完整要求.txt:
结果:
更新3:
我在这个答案中只使用了
Python 3.9.5
由于}的官方文件也鼓励使用{}服务器,如{}或{}
fastapi
是一个ASGI
框架,因此它将为ASGI
服务器(如uvicorn
或hypercorn
)提供更好的性能WSGI
类服务器gunicorn
无法提供类似uvicorn
的性能ASGI
服务器针对asynchronous
功能进行了优化。{https://fastapi.tiangolo.com/#installation
这种差异是由于您使用的底层web服务器造成的
一个类比可以是:
two cars, same brand, same options, just a different engine, what's the difference?
网络服务器并不完全像汽车,但我想你明白我想说的意思了
基本上,
gunicorn
是一个synchronous
web服务器,而uvicorn
是一个asynchronous
web服务器。由于您使用了fastapi
和await
关键字,我想您已经知道asyncio
/asynchornous programming
是什么了我不知道代码的差异,所以对我的答案持保留态度,但是
uvicorn
由于asynchronous
部分的原因,性能更高。我对时间差异的猜测是,如果您使用async
web服务器,它在启动时就已经配置为处理async
函数,而如果您使用sync
web服务器,它不是,并且为了抽象该部分,会有某种开销这不是一个正确的答案,但它给了你一个提示,告诉你区别在哪里
相关问题 更多 >
编程相关推荐