Slide 1

Slide 1 text

Asynchronous frameworks battle

Slide 2

Slide 2 text

Участники 1. Tornado 2. sanic 3. aiohttp 4. japronto 5. vibora 6. FastAPI 7. starlette 8. Quart

Slide 3

Slide 3 text

Турнирная сетка

Slide 4

Slide 4 text

Benchmarks config CPU: AMD FX(™) 6300 3.5Ghz 1 core, MEM: 2Gb, Ubuntu 18.04 Повышаем число соединений, пока не упремся в 80ms на персентиле 90. Как тестируем wrk -d300s -c100 -t1 --latency

Slide 5

Slide 5 text

aiohttp vibora

Slide 6

Slide 6 text

aiohttp ● Не совсем framework ● Миллион расширений (asyncpg, aiohttp_swagger, aiohttp_cors…) ● Streaming responses ● Websockets ● Сигналы ● Поддержка Context Variables (3.7 python) ● ready for prod

Slide 7

Slide 7 text

Vibora ● Cython ● Свой шаблонизатор (похож на jinja2) ● Свои схемы (асинхронные) ● Поддержка Streaming responses ● Type hints components ● Не готов к проду (Заново переписывается)

Slide 8

Slide 8 text

Vibora type hints components from vibora import Vibora, Request, Response from vibora import Route class Config: def __init__(self): self.name = 'Vibora Component' app = Vibora() app.add_component(Config()) @app.route('/') async def handler(request: Request, config: Config): current_config = request.get_component(Config) assert current_config is config return Response(config.name)

Slide 9

Slide 9 text

Результаты RPS p50 p90 p99 aiohttp c100 4324 22.14ms 25.42ms 39.41ms vibora c100 32867 2.89ms 3.76ms 9.48ms aiohttp cmax(300) 4012 71.45ms 84.64ms 103.38ms vibora cmax(1000) 30489 31.57ms 46.02ms 63.6ms

Slide 10

Slide 10 text

aiohttp vibora

Slide 11

Slide 11 text

tornado starlette

Slide 12

Slide 12 text

Tornado ● Python ● Streaming responses ● Websockets ● Свой шаблонизатор ● Ready for prod ● Ветеран труда

Slide 13

Slide 13 text

Starlette ● Python ● Под капотом ASGI (uvicorn, hypercorn, daphne) ● Не имеет жестких зависимостей. Опционально: ○ aiofiles для FileResponse и StaticFiles ○ jinja2 для Jinja2Templates ○ ujson для UJSONResponse ● CORS, GZip, Streaming responses ● Ready for prod

Slide 14

Slide 14 text

Результаты RPS p50 p90 p99 tornado c100 1875 51.7ms 57.93ms 73.29ms starlette c100 9674 9.8ms 11.16ms 22.44ms tornado cmax(140) 1844 73.28ms 83.81ms 101.52ms starlette cmax(500) 8625 50.22ms 87.02ms 122.54ms

Slide 15

Slide 15 text

tornado starlette

Slide 16

Slide 16 text

sanic quart

Slide 17

Slide 17 text

Sanic ● Python ● Свой вебсервер на uvloop + httptools ● Не поддерживает HTTP2 ● Поддерживает Websockets ● Поддерживает стримы (request, response, file) ● Нет встроенного шаблонизатора (есть jinja2-sanic) ● Ready for prod

Slide 18

Slide 18 text

Quart ● Python ● Под капотом ASGI ● Асинхронная версия Flask (можно мигрировать с Flask) ● Поддерживает Websockets и HTTP2 ● Streaming responses ● Шаблонизатор jinja2 ● Ready for prod

Slide 19

Slide 19 text

Результаты RPS p50 p90 p99 quart c100 2476 38.57ms 43.93ms 73.07ms sanic c100 9976 9.4ms 11.12ms 22.33ms quart cmax(150) 2228 61.01ms 80.58ms 145.75ms sanic cmax(500) 9247 45.79ms 81.42ms 108.3ms

Slide 20

Slide 20 text

sanic quart

Slide 21

Slide 21 text

japronto FastAPI

Slide 22

Slide 22 text

japronto ● C ● uvloop + picohttpparser ● Конвейерный HTTP сервер ● Поддержка Streaming responses ● Не готов к проду

Slide 23

Slide 23 text

FastAPI ● Python ● Под капотом ASGI (uvicorn, hypercorn, daphne) ● Starlette + pydantic ● Валидация данных на type hints ● SwaggerUI ● Ready for prod

Slide 24

Slide 24 text

Результаты RPS p50 p90 p99 japronto c100 28627 3.34ms 3.7ms 7.57ms fastapi c100 7033 13.71ms 14.89ms 24.69ms japronto cmax(1000) 27920 30.05ms 51.16ms 71.47ms fastapi cmax(350) 6470 49.68ms 72.86ms 107.72ms

Slide 25

Slide 25 text

japronto FastAPI

Slide 26

Slide 26 text

Турнирная сетка

Slide 27

Slide 27 text

Как тестируем echo "request" | vegeta attack -duration 300s -rate 300 pyflame -p PID -s 300 | flamegraph.pl > result.svg

Slide 28

Slide 28 text

starlette aiohttp

Slide 29

Slide 29 text

starlette

Slide 30

Slide 30 text

aiohttp

Slide 31

Slide 31 text

starlette aiohttp

Slide 32

Slide 32 text

sanic fastapi

Slide 33

Slide 33 text

sanic

Slide 34

Slide 34 text

fastapi

Slide 35

Slide 35 text

fastapi

Slide 36

Slide 36 text

Турнирная сетка

Slide 37

Slide 37 text

● async/await интерфейс (можно и в trio, и в curio) ● Общие серверные реализации (uvicorn, hypercorn, daphne, etc.) ● Общие middlwares ● Явное отделение сервера от приложения Немного про ASGI

Slide 38

Slide 38 text

async def read_body(receive): body = b'' more_body = True while more_body: message = await receive() body += message.get('body', b'') more_body = message.get('more_body', False) return body Пример async def app(scope, receive, send): body = await read_body(receive) await send({ 'type': 'http.response.start', 'status': 200, 'headers': [ [b'content-type', b'text/plain'], ] }) await send({ 'type': 'http.response.body', 'body': body, })

Slide 39

Slide 39 text

Аргументы: ● scope - словарь, содержащий информацию о входящем соединении ● receive - канал, по которому можно получать входящие сообщения с сервера ● send - канал, по которому отправляются исходящие сообщения на сервер

Slide 40

Slide 40 text

Scope { 'type': 'http', 'scheme': 'http', 'root_path': '', 'server': ('127.0.0.1', 8000), 'http_version': '1.1', 'method': 'GET', 'path': '/', 'headers': [ [b'host', b'127.0.0.1:8000'], [b'user-agent', b'curl/7.51.0'], [b'accept', b'*/*'] ] }

Slide 41

Slide 41 text

ASGI всех победит?

Slide 42

Slide 42 text

ASGI в PEP?

Slide 43

Slide 43 text

Sanic тоже

Slide 44

Slide 44 text

И вот теперь... ASGI mode is still in “beta” as of Sanic v19.6.

Slide 45

Slide 45 text

Результаты Победитель: Starlette Достойный противник: Sanic 3-4 место: aiohttp, FastAPI 5-8 место: Tornado, Vibora, japronto, Quart

Slide 46

Slide 46 text

Спасибо за внимание! Лайки, подписки, колокольчики :)