Ya no tienes que buscar más por otras webs porque estás al sitio perfecto, contamos con la solución que quieres y sin complicaciones.
Solución:
Esto parecía un poco interesante, así que realicé algunas pruebas con ApacheBench
:
Matraz
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Root(Resource):
def get(self):
return "message": "hello"
api.add_resource(Root, "/")
FastAPI
from fastapi import FastAPI
app = FastAPI(debug=False)
@app.get("/")
async def root():
return "message": "hello"
Ejecuté 2 pruebas para FastAPI, hubo una gran diferencia:
gunicorn -w 4 -k uvicorn.workers.UvicornWorker fast_api:app
uvicorn fast_api:app --reload
Así que aquí están los resultados de la evaluación comparativa para 5000 solicitudes con una simultaneidad de 500:
FastAPI con trabajadores de Uvicorn
Concurrency Level: 500
Time taken for tests: 0.577 seconds
Complete requests: 5000
Failed requests: 0
Total transferred: 720000 bytes
HTML transferred: 95000 bytes
Requests per second: 8665.48 [#/sec] (mean)
Time per request: 57.700 [ms] (mean)
Time per request: 0.115 [ms] (mean, across all concurrent requests)
Transfer rate: 1218.58 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 6 4.5 6 30
Processing: 6 49 21.7 45 126
Waiting: 1 42 19.0 39 124
Total: 12 56 21.8 53 127
Percentage of the requests served within a certain time (ms)
50% 53
66% 64
75% 69
80% 73
90% 81
95% 98
98% 112
99% 116
100% 127 (longest request)
FastAPI – Uvicorn puro
Concurrency Level: 500
Time taken for tests: 1.562 seconds
Complete requests: 5000
Failed requests: 0
Total transferred: 720000 bytes
HTML transferred: 95000 bytes
Requests per second: 3200.62 [#/sec] (mean)
Time per request: 156.220 [ms] (mean)
Time per request: 0.312 [ms] (mean, across all concurrent requests)
Transfer rate: 450.09 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 8 4.8 7 24
Processing: 26 144 13.1 143 195
Waiting: 2 132 13.1 130 181
Total: 26 152 12.6 150 203
Percentage of the requests served within a certain time (ms)
50% 150
66% 155
75% 158
80% 160
90% 166
95% 171
98% 195
99% 199
100% 203 (longest request)
Para matraz:
Concurrency Level: 500
Time taken for tests: 27.827 seconds
Complete requests: 5000
Failed requests: 0
Total transferred: 830000 bytes
HTML transferred: 105000 bytes
Requests per second: 179.68 [#/sec] (mean)
Time per request: 2782.653 [ms] (mean)
Time per request: 5.565 [ms] (mean, across all concurrent requests)
Transfer rate: 29.13 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 87 293.2 0 3047
Processing: 14 1140 4131.5 136 26794
Waiting: 1 1140 4131.5 135 26794
Total: 14 1227 4359.9 136 27819
Percentage of the requests served within a certain time (ms)
50% 136
66% 148
75% 179
80% 198
90% 295
95% 7839
98% 14518
99% 27765
100% 27819 (longest request)
Resultados totales
Matraz: Tiempo necesario para las pruebas: 27,827 segundos
FastAPI – Uvicorn: Tiempo necesario para las pruebas: 1,562 segundos
FastAPI – Trabajadores de Uvicorn: Tiempo necesario para las pruebas: 0,577 segundos
Con Uvicorn Workers FastAPI es casi 48 veces más rápido que Flask, lo cual es muy comprensible. ASGI vs WSGI, entonces corrí con 1 concurrencia:
FastAPI – UvicornWorkers: Tiempo necesario para las pruebas: 1,615 segundos
FastAPI – Uvicorn puro: Tiempo necesario para las pruebas: 2.681 segundos
Matraz: Tiempo necesario para las pruebas: 5.541 segundos
Ejecuté más pruebas para probar Flask con un servidor de producción.
5000 Solicitud 1000 Simultaneidad
Matraz con camarera
Server Software: waitress
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /
Document Length: 21 bytes
Concurrency Level: 1000
Time taken for tests: 3.403 seconds
Complete requests: 5000
Failed requests: 0
Total transferred: 830000 bytes
HTML transferred: 105000 bytes
Requests per second: 1469.47 [#/sec] (mean)
Time per request: 680.516 [ms] (mean)
Time per request: 0.681 [ms] (mean, across all concurrent requests)
Transfer rate: 238.22 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 4 8.6 0 30
Processing: 31 607 156.3 659 754
Waiting: 1 607 156.3 658 753
Total: 31 611 148.4 660 754
Percentage of the requests served within a certain time (ms)
50% 660
66% 678
75% 685
80% 691
90% 702
95% 728
98% 743
99% 750
100% 754 (longest request)
Gunicorn con trabajadores de Uvicorn
Server Software: uvicorn
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /
Document Length: 19 bytes
Concurrency Level: 1000
Time taken for tests: 0.634 seconds
Complete requests: 5000
Failed requests: 0
Total transferred: 720000 bytes
HTML transferred: 95000 bytes
Requests per second: 7891.28 [#/sec] (mean)
Time per request: 126.722 [ms] (mean)
Time per request: 0.127 [ms] (mean, across all concurrent requests)
Transfer rate: 1109.71 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 28 13.8 30 62
Processing: 18 89 35.6 86 203
Waiting: 1 75 33.3 70 171
Total: 20 118 34.4 116 243
Percentage of the requests served within a certain time (ms)
50% 116
66% 126
75% 133
80% 137
90% 161
95% 189
98% 217
99% 230
100% 243 (longest request)
Puro Uvicorn, pero esta vez 4 trabajadores uvicorn fastapi:app --workers 4
Server Software: uvicorn
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /
Document Length: 19 bytes
Concurrency Level: 1000
Time taken for tests: 1.147 seconds
Complete requests: 5000
Failed requests: 0
Total transferred: 720000 bytes
HTML transferred: 95000 bytes
Requests per second: 4359.68 [#/sec] (mean)
Time per request: 229.375 [ms] (mean)
Time per request: 0.229 [ms] (mean, across all concurrent requests)
Transfer rate: 613.08 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 20 16.3 17 70
Processing: 17 190 96.8 171 501
Waiting: 3 173 93.0 151 448
Total: 51 210 96.4 184 533
Percentage of the requests served within a certain time (ms)
50% 184
66% 209
75% 241
80% 260
90% 324
95% 476
98% 504
99% 514
100% 533 (longest request)
Estás usando el time.sleep()
función, en una async
punto final. time.sleep()
está bloqueando y nunca debe usarse en código asincrónico. Lo que deberías usar es probablemente el asyncio.sleep()
función:
import asyncio
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get('/')
async def root():
print('Sleeping for 10')
await asyncio.sleep(10)
print('Awake')
return 'message': 'hello'
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8000)
De esa manera, cada solicitud tardará ~ 10 segundos en completarse, pero podrá atender varias solicitudes al mismo tiempo.
En general, los marcos asíncronos ofrecen reemplazos para todas las funciones de bloqueo dentro de la biblioteca estándar (funciones de suspensión, funciones de E / S, etc.). Debe usar esos reemplazos al escribir código asincrónico y (opcionalmente) await
ellos.
Algunas bibliotecas y marcos sin bloqueo, como gevent, no ofrecen reemplazos. En su lugar, montan funciones de parche en la biblioteca estándar para que no sean bloqueantes. Sin embargo, este no es el caso, hasta donde yo sé, de los marcos y bibliotecas asincrónicas más recientes, porque están destinados a permitir que el desarrollador use la sintaxis async-await.
Creo que está bloqueando una cola de eventos en FastAPI, que es un marco asincrónico, mientras que en Flask, las solicitudes probablemente se ejecutan en un nuevo hilo. Mueva todas las tareas vinculadas a la CPU a procesos separados o, en su ejemplo de FastAPI, simplemente duerma en bucle de eventos (no use time.sleep aquí). En FastAPI, ejecute tareas vinculadas a IO de forma asincrónica