Revisiting the performance of Python frameworks for web development

Recently I had to start a project of a new web service, and I decided to test the maximum load capacity of Django, and at the same time compare it with Flask and AIOHTTP. The result seemed unexpected to me, so I will "just leave" it here.



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. :



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.



All Articles