Python
Flask

Flaskのデフォルトでは同時アクセスを処理できない

1. はじめに

Flaskのデフォルトでは複数のリクエストを同時に処理することができません。HTTPリクエストを並列処理するのではなくシングル(直列)処理で行うため、同時アクセスがあると最初のリクエストの処理が完了するまで待ちが発生します。
これは公式ドキュメントにも書かれています。

While lightweight and easy to use, Flask’s built-in server is not suitable for production as it doesn’t scale well and by default serves only one request at a time. Some of the options available for properly running Flask in production are documented here.

並列処理を有効にして同時アクセスを可能にするにはthreaded=Trueパラメータを設定します。

同時アクセスを処理できるようにする設定方法
# 同時アクセスができる(並列処理が可能)
app.run(host='localhost', port=3000, threaded=True)

flaskThreadedTrue.jpg

(注意)
WSGI(Web Server Gateway Interface)サーバを利用している場合はこの限りではありません。例えばGunicornの場合、pre-forkで複数プロセス(ワーカー)で処理を行うため、全体として並列処理が可能です。

2. ソースコード

同時アクセスの動作を確認するためのサンプルアプリ
# -*- coding: utf-8 -*-
from flask import Flask, make_response, jsonify
import time

# flask
app = Flask(__name__)

# rest api
@app.route('/hello/<string:value>', methods=['GET'])
def hello(value):
    result = 'hello {0}'.format(value)
    print('[start] ' + result)

    time.sleep(10)

    print('[end] ' + result)
    return(make_response(result))

# main
if __name__ == "__main__":
    # 同時アクセスができない(並列処理が不可能)
    # app.run(host='localhost', port=3000)

    # 同時アクセスができる(並列処理が可能)
    app.run(host='localhost', port=3000, threaded=True)

3. 動作確認

Webブラウザの画面(タブ)を2つ開いてURL①、URL②にそれぞれアクセスします。並列処理が有効であればコンソールに[start]が続くはずです。

threaded=Trueパラメータが設定されている場合
C:\Temp>python sampleApp.py
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
[start] hello shiro
[start] hello kuro
[end] hello shiro
127.0.0.1 - - [23/Jan/2018 20:54:30] "GET /hello/shiro HTTP/1.1" 200 -
[end] hello kuro
127.0.0.1 - - [23/Jan/2018 20:54:33] "GET /hello/kuro HTTP/1.1" 200 -

threaded=Trueパラメータが設定されている場合、[start]が続けて出力されているため並列処理になっていることが分かるかと思います。

デフォルトの場合(threadedパラメータが設定されていない)
C:\Temp>python sampleApp.py
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
[start] hello shiro
[end] hello shiro
127.0.0.1 - - [23/Jan/2018 21:10:37] "GET /hello/shiro HTTP/1.1" 200 -
[start] hello kuro
[end] hello kuro
127.0.0.1 - - [23/Jan/2018 21:10:48] "GET /hello/kuro HTTP/1.1" 200 -

デフォルトの場合、最初にアクセスのあったURL①の[end]が出力された後、URL②の[start]が出力されています。つまり並列処理になっておらず、最初の処理が終わるまで待ちになっているのが分かるかと思います。

4. さいごに

今回はFlaskのデフォルトでは複数のリクエストを同時に処理することができないこと、および並列処理を有効にするにはthreaded=Trueパラメータの設定が必要であることを説明しました。
実際のシステムではWSGIサーバを利用することが多いため、この仕様/制約を気にすることは少ないと思います。Flask単体で動作させる場合には注意する必要があります。