LoginSignup
52
52

More than 5 years have passed since last update.

wsgi, Bottle, Flask の速度差

Last updated at Posted at 2014-09-18

ISUCON の季節ですね。 ISUCON では慣習的に各言語で代表的なマイクロフレームワークが使われるのですが、 Python では今のところ Flask がずっと使われています。

Flask は確かに、簡単なサンプルアプリを書くときの見た目はマイクロフレームワークになっています。
しかし、構造的には沢山のフック、シグナルがあったりしていて、重量級の設計になっています。

Flask 本体と Werkzeug を合わせると数万行のサイズです。単なる Hello World アプリでも、数十の関数呼び出しが裏で動いています。

Bottle も、 Flask と同じくマルチスレッド対応で、スレッドローカルを使ったコンテキストスタックがある、拡張機能もあるフレームワークですが、構造は Flask よりも大分質素です。
ソースコードも1ファイル3000行代で、その分フレームワークのオーバーヘッドも Flask の半分程度になっています。

Hello アプリでちょっとした計測をしてみました。 MacBook Air 2013 Mid (Core i5 1.3GHz) で、シングルスレッド・シングルプロセスの Hello アプリを、 wrk -t1 -c1 でベンチマークします。 Python は CPython 3.4.1, Web サーバーは Meinheld (Github最新版) です。

wsgi:

$ wrk -t1 -c1 http://localhost:6000/
Running 10s test @ http://localhost:6000/
  1 threads and 1 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   118.89us   46.59us   0.99ms   91.40%
    Req/Sec     7.57k   622.67     9.90k    67.44%
  71708 requests in 10.00s, 11.08MB read
Requests/sec:   7170.95
Transfer/sec:      1.11MB

Bottle:

$ wrk -t1 -c1 http://localhost:6000/
Running 10s test @ http://localhost:6000/
  1 threads and 1 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   221.92us  678.78us  18.72ms   99.81%
    Req/Sec     4.86k   418.08     6.44k    78.08%
  46110 requests in 10.00s, 7.74MB read
Requests/sec:   4611.09
Transfer/sec:    792.53KB

Flask:

$ wrk -t1 -c1 http://localhost:6000/
Running 10s test @ http://localhost:6000/
  1 threads and 1 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   476.59us  134.74us   1.71ms   79.35%
    Req/Sec     2.11k   194.96     3.10k    65.86%
  19967 requests in 10.00s, 3.35MB read
Requests/sec:   1996.71
Transfer/sec:    343.18KB

Avg Latency の差で見た場合、 Bottle は約 100μs, Flask は約 350μs が生 wsgi に対するオーバーヘッドになっており、トータルの性能としても倍以上の差になっています。

Bottle は Jinja テンプレートもサポートしているので、初期アプリが Flask だったとしてもそこそこ簡単に Bottle に切り替えられるはずです。
HTML の部分をキャッシュして、 Memcached から取得したデータをくっつけて返すだけのパスが沢山叩かれるようなケースでは、このベース部分のパフォーマンスが無視できない差になってくるはずです。

最後に計測にしたソースコードを載せておきます。お試しください。

import flask
import bottle

app = flask.Flask(__name__)
bottle_app = bottle.app()

@bottle_app.route('/')
@app.route('/')
def index():
    return b"Hello, World"

def wsgi(env, start):
    c = b"Hello, World"
    start("200 OK", [('Content-Type', 'text/plain'), ('Content-Length', str(len(c)))])
    return [c]

# 起動方法
# Flask:  gunicorn -k meinheld.gmeinheld.MeinheldWorker -b :6000 app:app
# Bottle: gunicorn -k meinheld.gmeinheld.MeinheldWorker -b :6000 app:bottle_app
# wsgi:   gunicorn -k meinheld.gmeinheld.MeinheldWorker -b :6000 app:wsgi
52
52
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
52