FastAPI and Uvicorn is running synchronously and very slow
See original GitHub issueI’m new in FastAPI and i’m testing file uploads and asyncronous requests. However, when i perform several request with clients parallel and serial the FastAPI process each upload in Queue (synchronously) and very slow. I’m performing the API with uvicorn and gunicorn and with 1 worker. With both execution the time spent was the same.
My client send 4 files with approximately 20MB in parallel (or in serial) for FastAPI endpoint, however, it is storing the files one at a time and very slow.
I made the same upload with a aiohttp endpoint and the files was stored in approximately 0.6 seconds with client making request in parallel (multiprocessing) and 0.8 seconds with client making request in serial (in mean). When i made this uploads in FastAPI the files was stored in approximately 13 seconds with client making parallel request and 15 seconds with client making serial request (in mean)
Would I like know if i’m making anything wrong?
Server Code
# app.py
from fastapi import FastAPI, File, UploadFile
import random
import aiofiles
import os
app = FastAPI()
STORAGE_PATH = 'storage'
@app.post("/")
async def read_root(file: UploadFile=File('teste')):
fpath = os.path.join(
STORAGE_PATH, f'{random.randint(0, 5000)}_{file.filename}'
)
async with aiofiles.open(fpath, 'wb') as f:
content = await file.read()
await f.write(content)
return {"Test": "Test"}
# uvicorn app:app --host 0.0.0.0 --port 8000 --workers 1
# gunicorn -w=1 -k=uvicorn.workers.UvicornWorker --bind=0.0.0.0:8000 app:app
Client Code
FILES = ['f1.txt', 'f2.txt', 'f3.txt', 'f4.txt' ]
def request(fname):
files = {'file': open(fname,'rb')}
requests.post("http://localhost:8000/", files=files)
def req_mp():
start = datetime.now()
pool = Pool(4)
pool.map(request, FILES)
print(datetime.now() - start)
def req_serial():
start = datetime.now()
for fn in FILES:
request(fn)
print(datetime.now() - start)
Issue Analytics
- State:
- Created 3 years ago
- Comments:20 (7 by maintainers)
Top GitHub Comments
@igor-rodrigues1 sanic always reads files entirely into memory before passing control to your handler whereas fastapi via starlette uses a
tempfile.SpooledTemporaryFile
and thus rolls data over onto disk once it grows beyond 1 MB. if you overwrite the default spooling threshold forUploadFile
like… I think you may see performance somewhat similar to that of sanic & uvicorn as it should eliminate the file I/O trip
Found streaming_form_data which does multipart/form-data parsing much faster, as it uses Cython. In his blog the author wrote that byte-wise parsing in pure Python is slow, so thats why multipart is slow in the current implementation of starlette.
Created a gist with an example.