Skip to content

Instantly share code, notes, and snippets.

@fluential
Forked from samuelcolvin/aiohttp_vs_sanic.md
Created March 3, 2020 19:28
Show Gist options
  • Save fluential/149ddd85f67bd67925aa1c885fb0d810 to your computer and use it in GitHub Desktop.
Save fluential/149ddd85f67bd67925aa1c885fb0d810 to your computer and use it in GitHub Desktop.
comparing aiohttp and sanic performance

Requirements

python 3.6, postgres, pip install aiohttp uvloop ujson asyncpg sanic

aiohttp & uvloop

➤ wrk -d 10 -c 100 -t 12 --timeout 8 http://localhost:8000  # aiohttp
Running 10s test @ http://localhost:8000
  12 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    13.52ms    1.58ms  43.44ms   93.29%
    Req/Sec   594.37     48.42   646.00     81.33%
  71051 requests in 10.01s, 11.32MB read
Requests/sec:   7099.30
Transfer/sec:      1.13MB
➤ wrk -d 10 -c 100 -t 12 --timeout 8 http://localhost:8000/db  # aiohttp
Running 10s test @ http://localhost:8000/db
  12 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    27.43ms    6.93ms 151.69ms   97.44%
    Req/Sec   296.99     24.29   340.00     87.14%
  35327 requests in 10.01s, 6.46MB read
Requests/sec:   3528.96
Transfer/sec:    661.25KB

sanic & uvloop

➤ wrk -d 10 -c 100 -t 12 --timeout 8 http://localhost:8000  # sanic
Running 10s test @ http://localhost:8000
  12 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.55ms  724.50us  17.67ms   94.63%
    Req/Sec     1.77k   499.35    18.67k    98.92%
  211459 requests in 10.10s, 27.43MB read
Requests/sec:  20936.08
Transfer/sec:      2.72MB
➤ wrk -d 10 -c 100 -t 12 --timeout 8 http://localhost:8000/db  # sanic
Running 10s test @ http://localhost:8000/db
  12 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    16.98ms    6.05ms 124.18ms   98.70%
    Req/Sec   483.90     40.57   540.00     94.46%
  57605 requests in 10.01s, 8.82MB read
Requests/sec:   5755.33
Transfer/sec:      0.88MB
import asyncio
import random
import ujson
from aiohttp import web
from shared import setup_db
async def startup(app):
app['db'] = await setup_db(app.loop)
async def cleanup(app):
await app['db'].close()
async def index(request):
data = {'message': 'hello world'}
body = ujson.dumps(data)
return web.Response(body=body.encode(), content_type='application/json')
async def db(request):
user_id = random.randrange(1, 1000)
async with request.app['db'].acquire() as conn:
username = await conn.fetchval('SELECT name from users WHERE id=$1', user_id)
data = {'message': f'hello {username}'}
body = ujson.dumps(data)
return web.Response(body=body.encode(), content_type='application/json')
# import tokio
# asyncio.set_event_loop_policy(tokio.TokioLoopPolicy())
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
app = web.Application()
app.on_startup.append(startup)
app.on_cleanup.append(cleanup)
app.router.add_get('/', index)
app.router.add_get('/db', db)
web.run_app(app, port=8000)
import random
from sanic import Sanic
from sanic.response import json
from shared import setup_db
app = Sanic()
@app.listener('before_server_start')
async def register_db(app, loop):
app.db = await setup_db(loop)
@app.listener('after_server_stop')
async def cleanup(app, loop):
await app.db.close()
@app.route('/')
async def index(request):
data = {'message': 'hello world'}
return json(data)
@app.route('/db')
async def get_form_db(request):
user_id = random.randrange(1, 1000)
async with request.app.db.acquire() as conn:
username = await conn.fetchval('SELECT name from users WHERE id=$1', user_id)
data = {'message': f'hello {username}'}
return json(data)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, log_config=None)
import random
import string
import asyncpg
PG_DSN_NO_DB = 'postgres://postgres:<your password>@localhost:5432'
DB_NAME = 'foobar'
PG_DSN = PG_DSN_NO_DB + '/' + DB_NAME
DB_EXISTS = 'SELECT EXISTS (SELECT datname FROM pg_catalog.pg_database WHERE datname=$1)'
CREATE_TABLES = """\
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(63) NOT NULL
);
"""
async def setup_db(loop):
conn = await asyncpg.connect(dsn=PG_DSN_NO_DB)
try:
db_exists = await conn.fetchval(DB_EXISTS, DB_NAME)
if not db_exists:
await conn.execute('CREATE DATABASE {}'.format(DB_NAME))
finally:
await conn.close()
conn = await asyncpg.connect(dsn=PG_DSN)
try:
await conn.execute(CREATE_TABLES)
names = [
[''.join(random.choices(string.ascii_letters, k=random.randrange(10, 50)))]
for _ in range(1000)
]
await conn.executemany('INSERT INTO users (name) VALUES ($1);', names)
finally:
await conn.close()
return await asyncpg.create_pool(PG_DSN, loop=loop, max_size=100)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment