Python web-frameworksThis article provides information about the Python frameworks and compares them with WSGI-synchronous solutions from the strengths and weaknesses point of view. The following frameworks considered (description taken from their sites) - Aiohttp 0.16.3 - asynchronous framework based on Asyncio;
- Bottle 0.12.8 - fast, simple and lightweight WSGI microframework;
- Django 1.8.2 - web framework for perfectionists with deadlines burning;
- Falcon 0.3.0 - high-performance framework for building cloud API;
- Flask 0.10.1 - microframework based on Werkzeug, Jinja2 and good intentions;
- Muffin 0.0.88 - asynchronous framework based on Asyncio è Aiohttp;
- Pyramid 1.5.7 - small, fast and intuitive web framework;
- Tornado 4.2 - asynchronous networking library and a web framework;
Test procedure Tests were carried out on Amazon EC2 t2.medium server. To create a load used WRK utility running on the same server with the following parameters: wrk -d30s -t12 -c400 [URL] All applications (except for the Tornado) were run using Gunicorn (2 for each process). For synchronous WSGI libraries used Meinheld worker. Tornado has launched the process of using including web-server. All tests were conducted using Python 2.7.6. Each application was tested on three main scenarios: - JSON-test - encode small object in JSON and return to the client.
- Remote-test - download response from another server and return it to the client.
- Complete-test - using ORM to load a collection of objects from the database, add to it and render the list in a template.
The first scenario is the simplest request of object to JSON encoding. It shows the speed of the HTTP-request processing. The second scenario shows how well the framework copes with long waiting transactions while processing the request. The third scenario is an integrated test and simulates real life by using of a database, ORM, templating work. Postgresql database used as default. Source code is presented at Github. Results
Name | 50% (ms) | 75% (ms) | Avg (ms) | Req/s | Falcon | 19.24 | 19.81 | 19.19 | 20677.13 | Bottle | 24.77 | 26.23 | 25.06 | 15761.45 | Pyramid | 41.75 | 43.49 | 41.63 | 9402.69 | Flask | 64.32 | 71.59 | 65.68 | 6023.4 | Aiohttp | 91.67 | 103.1 | 108.01 | 4093.41 | Django | 103.2 | 112.19 | 103.36 | 3696.9 | Muffin | 108.07 | 115.09 | 171.56 | 3575.36 | Tornado | 138.24 | 149.84 | 136.87 | 2829.72 | In the first test, simple synchronous frameworks were the best. Asynchronous frameworks showed worse results. Name | 50% (ms) | 75% (ms) | Avg (ms) | Req/s | Timeouts | Aiohttp | 358.08 | 369.08 | 338.94 | 1120.27 | | Muffin | 372.95 | 428.75 | 376.98 | 1019.76 | | Tornado | 1994.39 | 2069.25 | 1928.31 | 194.37 | | Pyramid | 3295.1 | 10518.92 | 6673.78 | 19.35 | 338 | Falcon | 3196.23 | 12976.84 | 6696.17 | 19.28 | 328 | Flask | 3306.88 | 11690.8 | 6824.88 | 19.16 | 363 | Bottle | 3363.74 | 9911.84 | 6403.92 | 19.09 | 335 | Django | 3317.64 | 12954.23 | 6918.64 | 18.96 | 300 | To understand the results of this test is necessary to clarify that the application accesses the nginx configured to respond with 100ms latency. Because of this, the results are very close to synchronous frameworks. Name | 50% (ms) | 75% (ms) | Avg (ms) | Req/s | Timeouts | Aiohttp | 151.78 | 156.9 | 254.75 | 1004.82 | 236
| Muffin | 420.14 | 485.4 | 1552.7 | 819.62 | | Bottle | 613.5 | 630.17 | 1062.86 | 451.34 | 178 | Tornado | 937.37 | 988.86 | 910.06 | 418.36 | | Falcon | 766.75 | 805.35 | 1457.99 | 350.26 | 81 | Pyramid | 562.44 | 601.49 | 812.43 | 248.42 | 235 | Flask | 1032.63 | 1649.89 | 1465.25 | 222.78 | 496 | Django | 1610.46 | 1976.44 | 2632.36 | 88.57 | 42 | Based on test results, I suggest using Bottle framework as an optimal solution. Besides, this framework is rather simple and intuitive comparing to the others.
|