Я не могу воспроизвести ваши результаты.
Моя среда: ubuntu на WSL2 в Windows 10
соответствующие части моего pip freeze
вывода:
fastapi==0.65.1
gunicorn==20.1.0
uvicorn==0.14.0
Я немного изменил код:
import asyncio, time
from fastapi import FastAPI, Path
from datetime import datetime
import statistics
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)
time_delta= (datetime.now()-start_time).microseconds
times.append(time_delta)
times_average = statistics.mean(times)
return {"delays":[delay1,delay2],"total_time_taken":(datetime.now()-total_start_time).microseconds,"times_avarage":times_average,"times":times}
За исключением первой загрузки веб-сайта, мои результаты для обоих методов почти одинаковы.
В большинстве случаев для обоих методов времена находятся между 0:00:00.000530
и 0:00:00.000620
.
Первая попытка для каждого занимает больше времени: около 0:00:00.003000
. Однако после того, как я перезапустил Windows и снова попробовал эти тесты, я заметил, что у меня больше не увеличивается время выполнения первых запросов после запуска сервера (я думаю, это благодаря большому количеству свободной оперативной памяти после перезапуска)
Примеры не первых прогонов (3 попытки):
# `uvicorn performance_test:app --port 8083`
{"delays":[0.0,0.0],"total_time_taken":553,"times_avarage":4.4,"times":[15,7,5,4,4,4,4,5,5,4,4,5,4,4,5,4,4,5,4,4,5,4,4,5,4,4,4,5,4,4,5,4,4,5,4,4,4,4,4,5,4,5,5,4,4,4,4,4,4,5,4,4,4,5,4,4,4,4,4,4,5,4,4,5,4,4,4,4,5,4,4,5,4,4,4,4,4,5,4,4,5,4,4,5,4,4,5,4,4,4,4,4,4,4,5,4,4,4,5,4]}
{"delays":[0.0,0.0],"total_time_taken":575,"times_avarage":4.61,"times":[15,6,5,5,5,5,5,5,5,5,5,4,5,5,5,5,4,4,4,4,4,5,5,5,4,5,4,4,4,5,5,5,4,5,5,4,4,4,4,5,5,5,5,4,4,4,4,5,5,4,4,4,4,4,4,4,4,5,5,4,4,4,4,5,5,5,5,5,5,5,4,4,4,4,5,5,4,5,5,4,4,4,4,4,4,5,5,5,4,4,4,4,5,5,5,5,4,4,4,4]}
{"delays":[0.0,0.0],"total_time_taken":548,"times_avarage":4.31,"times":[14,6,5,4,4,4,4,4,4,4,5,4,4,4,4,4,4,5,4,4,5,4,4,4,4,4,4,4,5,4,4,4,5,4,4,4,4,4,4,4,4,5,4,4,4,4,4,4,5,4,4,4,4,4,5,5,4,4,4,4,4,4,4,5,4,4,4,4,4,5,4,4,5,4,4,5,4,4,5,4,4,4,4,4,4,4,5,4,4,5,4,4,5,4,4,5,4,4,4,4]}
# `gunicorn performance_test:app -b localhost:8084 -k uvicorn.workers.UvicornWorker --workers 1`
{"delays":[0.0,0.0],"total_time_taken":551,"times_avarage":4.34,"times":[13,6,5,5,5,5,5,4,4,4,5,4,4,4,4,4,5,4,4,5,4,4,5,4,4,4,4,4,5,4,4,4,4,4,5,4,4,4,4,4,4,4,5,4,4,5,4,4,4,4,4,4,4,4,5,4,4,4,4,4,4,4,5,4,4,4,4,4,4,4,4,4,5,4,4,5,4,5,4,4,5,4,4,4,4,5,4,4,5,4,4,4,4,4,4,4,5,4,4,5]}
{"delays":[0.0,0.0],"total_time_taken":558,"times_avarage":4.48,"times":[14,7,5,5,5,5,5,5,4,4,4,4,4,4,5,5,4,4,4,4,5,4,4,4,5,5,4,4,4,5,5,4,4,4,5,4,4,4,5,5,4,4,4,4,5,5,4,4,5,5,4,4,5,5,4,4,4,5,4,4,5,4,4,5,5,4,4,4,5,4,4,4,5,4,4,4,5,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4]}
{"delays":[0.0,0.0],"total_time_taken":550,"times_avarage":4.34,"times":[15,6,5,4,4,4,4,4,4,5,4,4,4,4,4,5,4,4,5,4,4,5,4,4,4,4,4,5,4,4,4,4,5,5,4,4,4,4,5,4,4,4,4,4,5,4,4,5,4,4,5,4,4,5,4,4,5,4,4,5,4,4,4,4,4,4,5,4,4,5,4,4,4,4,4,4,4,4,4,5,4,4,5,4,4,4,4,4,4,4,4,5,4,4,5,4,4,4,4,4]}
Примеры непервых запусков с комментариями await asyncio.sleep(delay1)
(3 попытки):
# `uvicorn performance_test:app --port 8083`
{"delays":[0.0,0.0],"total_time_taken":159,"times_avarage":0.6,"times":[3,1,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0]}
{"delays":[0.0,0.0],"total_time_taken":162,"times_avarage":0.49,"times":[3,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1]}
{"delays":[0.0,0.0],"total_time_taken":156,"times_avarage":0.61,"times":[3,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1]}
# `gunicorn performance_test:app -b localhost:8084 -k uvicorn.workers.UvicornWorker --workers 1`
{"delays":[0.0,0.0],"total_time_taken":159,"times_avarage":0.59,"times":[2,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0]}
{"delays":[0.0,0.0],"total_time_taken":165,"times_avarage":0.62,"times":[3,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1]}
{"delays":[0.0,0.0],"total_time_taken":164,"times_avarage":0.54,"times":[2,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1]}
Я сделал скрипт Python, чтобы более точно измерить те времена:
import statistics
import requests
from time import sleep
number_of_tests=1000
sites_to_test=[
{
'name':'only uvicorn ',
'url':'http://127.0.0.1:8083/delay/0.0/0.0'
},
{
'name':'gunicorn+uvicorn',
'url':'http://127.0.0.1:8084/delay/0.0/0.0'
}]
for test in sites_to_test:
total_time_taken_list=[]
times_avarage_list=[]
requests.get(test['url']) # first request may be slower, so better to not measure it
for a in range(number_of_tests):
r = requests.get(test['url'])
json= r.json()
total_time_taken_list.append(json['total_time_taken'])
times_avarage_list.append(json['times_avarage'])
# sleep(1) # results are slightly different with sleep between requests
total_time_taken_avarage=statistics.mean(total_time_taken_list)
times_avarage_avarage=statistics.mean(times_avarage_list)
print({'name':test['name'], 'number_of_tests':number_of_tests, 'total_time_taken_avarage':total_time_taken_avarage, 'times_avarage_avarage':times_avarage_avarage})
Полученные результаты:
{'name': 'only uvicorn ', 'number_of_tests': 2000, 'total_time_taken_avarage': 586.5985, 'times_avarage_avarage': 4.820865}
{'name': 'gunicorn+uvicorn', 'number_of_tests': 2000, 'total_time_taken_avarage': 571.8415, 'times_avarage_avarage': 4.719035}
Результаты с комментариями await asyncio.sleep(delay1)
{'name': 'only uvicorn ', 'number_of_tests': 2000, 'total_time_taken_avarage': 151.301, 'times_avarage_avarage': 0.602495}
{'name': 'gunicorn+uvicorn', 'number_of_tests': 2000, 'total_time_taken_avarage': 144.4655, 'times_avarage_avarage': 0.59196}
Я также сделал другую версию вышеупомянутого скрипта, который меняет URL-адреса каждый 1 запрос (это дает немного большее время):
import statistics
import requests
from time import sleep
number_of_tests=1000
sites_to_test=[
{
'name':'only uvicorn ',
'url':'http://127.0.0.1:8083/delay/0.0/0.0',
'total_time_taken_list':[],
'times_avarage_list':[]
},
{
'name':'gunicorn+uvicorn',
'url':'http://127.0.0.1:8084/delay/0.0/0.0',
'total_time_taken_list':[],
'times_avarage_list':[]
}]
for test in sites_to_test:
requests.get(test['url']) # first request may be slower, so better to not measure it
for a in range(number_of_tests):
for test in sites_to_test:
r = requests.get(test['url'])
json= r.json()
test['total_time_taken_list'].append(json['total_time_taken'])
test['times_avarage_list'].append(json['times_avarage'])
# sleep(1) # results are slightly different with sleep between requests
for test in sites_to_test:
total_time_taken_avarage=statistics.mean(test['total_time_taken_list'])
times_avarage_avarage=statistics.mean(test['times_avarage_list'])
print({'name':test['name'], 'number_of_tests':number_of_tests, 'total_time_taken_avarage':total_time_taken_avarage, 'times_avarage_avarage':times_avarage_avarage})
Полученные результаты:
{'name': 'only uvicorn ', 'number_of_tests': 2000, 'total_time_taken_avarage': 589.4315, 'times_avarage_avarage': 4.789385}
{'name': 'gunicorn+uvicorn', 'number_of_tests': 2000, 'total_time_taken_avarage': 589.0915, 'times_avarage_avarage': 4.761095}
Результаты с прокомментированными await asyncio.sleep(delay1)
{'name': 'only uvicorn ', 'number_of_tests': 2000, 'total_time_taken_avarage': 152.8365, 'times_avarage_avarage': 0.59173}
{'name': 'gunicorn+uvicorn', 'number_of_tests': 2000, 'total_time_taken_avarage': 154.4525, 'times_avarage_avarage': 0.59768}
Этот ответ должен помочь вам лучше отладить ваши результаты.
Я думаю, что будет полезно изучить ваши результаты, если вы поделитесь более подробной информацией о своей ОС / машине.
Также перезагрузите компьютер / сервер, это может повлиять.
Обновление 1:
Я вижу, что я использовал более новую версию uvicorn 0.14.0
, чем указано в вопросе 0.13.4
. Я также тестировал более старую версию 0.13.4
, но результаты аналогичны, я все еще не могу воспроизвести ваши результаты.
Обновление 2:
Я провел еще несколько тестов и заметил кое-что интересное:
с uvloop в файле requirements.txt:
весь файл requirements.txt:
uvicorn==0.14.0
fastapi==0.65.1
gunicorn==20.1.0
uvloop==0.15.2
Полученные результаты:
{'name': 'only uvicorn ', 'number_of_tests': 500, 'total_time_taken_avarage': 362.038, 'times_avarage_avarage': 2.54142}
{'name': 'gunicorn+uvicorn', 'number_of_tests': 500, 'total_time_taken_avarage': 366.814, 'times_avarage_avarage': 2.56766}
без uvloop в файле requirements.txt:
весь файл requirements.txt:
uvicorn==0.14.0
fastapi==0.65.1
gunicorn==20.1.0
Полученные результаты:
{'name': 'only uvicorn ', 'number_of_tests': 500, 'total_time_taken_avarage': 595.578, 'times_avarage_avarage': 4.83828}
{'name': 'gunicorn+uvicorn', 'number_of_tests': 500, 'total_time_taken_avarage': 584.64, 'times_avarage_avarage': 4.7155}
Обновление 3:
В этом ответе я использовал только Python 3.9.5
.
person
Karol Zlot
schedule
08.06.2021