The diagrams below show the results of the simplest Apache Benchmark for the Django frameworks version 3.1, Flask 1.1 and AIOHTTP 3.7. AIOHTTP runs in "regular" single-threaded asynchronous mode, Django and Flask are served by a synchronous WSGI server Gunicorn with the number of threads equal to the number of available processor cores * 2. ASGI did not participate in the test.
Test conditions
PostgreSQL. :
, , , .
AIOHTTP asyncpg, Django Flask — SQLAlchemy ORM ( ) psycopg2.
Django (django-admin startproject, manage.py startapp . .), ListView. Flask AIOHTTP «Hello, world», .
SELECT r.id, r.auth_user_id, r.status, r.updated, r.label, r.content, u.username,
ARRAY_AGG(t.tag) tag, COUNT(*) OVER() cnt,
(
SELECT COUNT(*) FROM record r2
WHERE
r2.parent_id IS NOT NULL
AND r2.parent_id = r.id
AND r2.status = 'new'
) AS parts
FROM record r
JOIN auth_user u ON u.id = r.auth_user_id
LEFT JOIN tag t ON t.kind_id = r.id AND t.kind = 'rec'
WHERE r.parent_id IS NULL AND r.status = 'new'
GROUP BY r.id, u.username
ORDER BY r.updated DESC
LIMIT 10 OFFSET 0
, , , .
AIOHTTP asyncpg, Django Flask — SQLAlchemy ORM ( ) psycopg2.
Django (django-admin startproject, manage.py startapp . .), ListView. Flask AIOHTTP «Hello, world», .
Results of running the test on a local machine (4 CPU cores):
UPD: as they rightly write in the comments, for an honest comparison, one should either run AIOHTTP behind Gunicorn, or reduce the number of workers to 1.
The same test on a real single-processor VDS (ping is about 45 ms):
During the test, AIOHTTP used 100% of one CPU core, Flask and Django - 100% of all available cores.
conclusions
In fact, comparing asynchronous and multithreaded applications is not entirely correct - they solve different problems. Therefore, the result looks quite logical: in the local test, AIOHTTP simply had fewer resources, under equal conditions the performance is leveled.
But the modest result of Flask is difficult to explain, I could not "overclock" this framework.