In [1]:
import os
import signal
import gunicorn.app.base
from multiprocessing import Process
from contextlib import contextmanager

HOST, PORT = "127.0.0.1", "8080"

class BenchmarkApplication(gunicorn.app.base.BaseApplication):

    def __init__(self, app, worker_class, threads):
        self.worker_class = worker_class
        self.threads = threads
        self.application = app
        super().__init__()

    def load_config(self):
        self.cfg.set("bind", f"{HOST}:{PORT}")
        self.cfg.set("workers", 2)
        self.cfg.set("worker_class", self.worker_class)
        self.cfg.set("threads", self.threads)
        
    def load(self):
        return self.application

def run(app_func, worker, threads):
    app = app_func()
    BenchmarkApplication(app, worker, threads).run()
    
@contextmanager
def app_running(app_func, worker, threads=1):
    p = Process(target=lambda: run(app_func, worker, threads))
    p.start()
    time.sleep(1)
    print("allowed sleep")
    yield 
    os.kill(p.pid, signal.SIGINT)
    print("kill sent")
    p.join(timeout=5)
In [4]:
%matplotlib inline
import time
from multiprocessing import Process

class Stats:
    def __init__(self):
        self.request_latencies = []
        self.timed_out = 0
        self.elapsed_time = 0

async def fetch(stats, session, url):
    start_time = time.time()
    try:
        async with session.get(url) as response:
            await response.text()
    except:
        stats.timed_out += 1
    else:
        elapsed_time = time.time() - start_time
        stats.request_latencies.append(elapsed_time)

import aiohttp
TOTAL_COUNT = 5000
MAX_CONNECTIONS = 200

async def benchmark(root="http://localhost:8080/"):
    url = root + "foo"
    stats = Stats()
    start_time = time.time()
    conn = aiohttp.TCPConnector(limit=MAX_CONNECTIONS)
    async with aiohttp.ClientSession(connector=conn) as session:
        task_list = []
        for i in range(TOTAL_COUNT):
            task_list.append(fetch(stats, session, url))
        await asyncio.gather(*task_list)
    elapsed_time = time.time() - start_time
    stats.elapsed_time = elapsed_time
    return stats
In [ ]:
from aiohttp import web
import asyncio

def create_aiohttp_app():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    async def handle(request):
        name = request.match_info.get('name', "Anonymous")
        await asyncio.sleep(0.1)
        text = "Hello, " + name
        return web.Response(text=text)

    aiohttp_app = web.Application()
    aiohttp_app.router.add_get('/', handle)
    aiohttp_app.router.add_get('/{name}', handle)
    return aiohttp_app
    
import asyncio
loop = asyncio.get_event_loop()
with app_running(create_aiohttp_app, "aiohttp.worker.GunicornWebWorker"):
     stats = loop.run_until_complete(benchmark())
    
import matplotlib.pyplot as plt

print(stats.elapsed_time)
plt.hist(stats.request_latencies, bins=100)
[2017-07-05 21:41:30 -0700] [7641] [INFO] Starting gunicorn 19.7.1
[2017-07-05 21:41:30 -0700] [7641] [INFO] Listening at: http://127.0.0.1:8080 (7641)
[2017-07-05 21:41:30 -0700] [7641] [INFO] Using worker: aiohttp.worker.GunicornWebWorker
[2017-07-05 21:41:30 -0700] [7642] [INFO] Booting worker with pid: 7642
[2017-07-05 21:41:30 -0700] [7643] [INFO] Booting worker with pid: 7643
allowed sleep
In [3]:
from flask import Flask
flask_app = Flask(__name__)
import time

@flask_app.route("/<name>")
def hello(name):
    time.sleep(0.1)
    return "Hello World!"

import asyncio
loop = asyncio.get_event_loop()
with app_running(lambda: flask_app, "sync", threads=10):
    stats = loop.run_until_complete(benchmark())
    
import matplotlib.pyplot as plt

print(stats.elapsed_time)
plt.hist(stats.request_latencies, bins=100)
[2017-07-05 21:40:45 -0700] [7625] [INFO] Starting gunicorn 19.7.1
[2017-07-05 21:40:45 -0700] [7625] [INFO] Listening at: http://127.0.0.1:8080 (7625)
[2017-07-05 21:40:45 -0700] [7625] [INFO] Using worker: threads
[2017-07-05 21:40:45 -0700] [7626] [INFO] Booting worker with pid: 7626
[2017-07-05 21:40:45 -0700] [7629] [INFO] Booting worker with pid: 7629
allowed sleep
[2017-07-05 21:41:04 -0700] [7625] [INFO] Handling signal: int
[2017-07-05 21:41:04 -0700] [7626] [INFO] Worker exiting (pid: 7626)
[2017-07-05 21:41:04 -0700] [7629] [INFO] Worker exiting (pid: 7629)
kill sent
[2017-07-05 21:41:04 -0700] [7625] [INFO] Shutting down: Master
18.032105922698975
Out[3]:
(array([ 40.,  40.,  40.,  23.,  37.,  40.,  32.,  28.,  40.,  40.,  22.,
         38.,  36.,  19.,  22.,  23.,  17.,  11.,  11.,   7.,   8.,   8.,
          7.,   5.,   8.,   7.,   5.,   8.,   7.,   6.,   7.,   8.,   5.,
          7.,   8.,   6.,   9.,   5.,   5.,   5.,   4.,   6.,   5.,   4.,
          6.,   5.,   4.,   6.,   4.,   5.,   6.,   4.,   5.,   6.,   4.,
          5.,   6.,   5.,   5.,   5.,   4.,   6.,   5.,   4.,   6.,   5.,
          4.,   6.,   5.,   4.,   6.,   5.,   5.,   5.,   5.,   5.,   5.,
          5.,   5.,   5.,   5.,   5.,   5.,   5.,   5.,   5.,   5.,   5.,
          5.,   5.,   5.,   5.,   5.,   4.,   6.,   5.,   5.,   5.,   5.,
          5.]), array([  0.42265677,   0.59651399,   0.7703712 ,   0.94422842,
          1.11808563,   1.29194285,   1.46580006,   1.63965728,
          1.81351449,   1.9873717 ,   2.16122892,   2.33508613,
          2.50894335,   2.68280056,   2.85665778,   3.03051499,
          3.20437221,   3.37822942,   3.55208663,   3.72594385,
          3.89980106,   4.07365828,   4.24751549,   4.42137271,
          4.59522992,   4.76908714,   4.94294435,   5.11680156,
          5.29065878,   5.46451599,   5.63837321,   5.81223042,
          5.98608764,   6.15994485,   6.33380207,   6.50765928,
          6.68151649,   6.85537371,   7.02923092,   7.20308814,
          7.37694535,   7.55080257,   7.72465978,   7.898517  ,
          8.07237421,   8.24623142,   8.42008864,   8.59394585,
          8.76780307,   8.94166028,   9.1155175 ,   9.28937471,
          9.46323193,   9.63708914,   9.81094635,   9.98480357,
         10.15866078,  10.332518  ,  10.50637521,  10.68023243,
         10.85408964,  11.02794686,  11.20180407,  11.37566128,
         11.5495185 ,  11.72337571,  11.89723293,  12.07109014,
         12.24494736,  12.41880457,  12.59266179,  12.766519  ,
         12.94037621,  13.11423343,  13.28809064,  13.46194786,
         13.63580507,  13.80966229,  13.9835195 ,  14.15737672,
         14.33123393,  14.50509115,  14.67894836,  14.85280557,
         15.02666279,  15.20052   ,  15.37437722,  15.54823443,
         15.72209165,  15.89594886,  16.06980608,  16.24366329,
         16.4175205 ,  16.59137772,  16.76523493,  16.93909215,
         17.11294936,  17.28680658,  17.46066379,  17.63452101,  17.80837822]), <a list of 100 Patch objects>)
In [ ]: