Cython'им fastapi-проект: сравниваем скорость pure python и cython имплементаций
Что такое fastapi?
fastapi - имхо, самый лучший фреймворк для веб-разработки на Python, основными фичами которого являются:
- высокая производительность относительно других фреймворков на Python за счет использования starlette и uvicorn в качестве ASGI-сервера, сравним по скорости с фреймворками на Go и NodeJS
- простота использования - благодаря pydantic (для валидации запросов) и целой куче готовых подмодулей для любых задач (websockets, background tasks, система зависимостей компонентов приложения, middlewares и многое другое) очень легко и интуитивно понятно, как написать какую-то вещь
- полная типизация фреймворка и поддержка редакторами - меньше времени на дебаг и подсказки IDE
- автоматическая генерация документации (по схеме OpenAPI, Swagger и Redoc)
Что такое cython?
Cython - это промежуточный слой между Python и C/C++. Cython позволяет писать обычный Python-код, добавляя функции из стандаратной библиотеки языков C/C++ и ускоряя код за счет испол ьзования C-типов (что, впрочем, не обязательно), который затем напрямую транслируется в C-код.
Что будем делать?
В этом блоге попробуем ускорить и без того довольно быстрый проект на fastapi, ситонизируя (cythonize) его. Для примера возьмем вот такой код (выдрал минимальный код из одного из текущих проектов, поэтому такая структура):
from fastapi import APIRouter
router = APIRouter(
prefix="/ftl.",
tags=["ftl"]
)
@router.get("test")
async def test_method():
return {"ping": "pong"}
from .ftl import ftl
from fastapi import FastAPI
import uvicorn
from routers import ftl
app = FastAPI()
app.include_router(ftl.router, prefix="/method")
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
uvicorn.run("main:app", host="127.0.0.1", port=5000, log_level="critical")
Тут мы создаем роутер для группы методов под названием ftl
с одним методом - ftl.test
.
Обычно для запуска fastapi-приложений используют uvicorn из терминала (примерно так):
python3 -m uvicorn main:app --host 0.0.0.0 --port 5000
Но так как мы скомпилируем проект в один бинарник, который можно будет запускать через ./app
, запуск ASGI-сервера мы засунули в код проекта.
Теперь установим нужные зависимости (желательно в виртуальном окружении):
pip3 install fastapi
pip3 install cython
pip3 install 'uvicorn[standard]'
Обратите внимание, что мы ставим не обычный uvicorn
, а uvicorn[standart]
- его ситонизированную версию. Это даст некоторую прибавку в скорости даже при запуске pure python кода.