[Python] Flask vs Fast API 速度を比較してみた

#Background
趣味で作成しているサービスのバックエンドの自作APIとしてFlaskを使用していました。
数日前、Qiitaを見ているとこんな記事がありました。


[python製の最新APIフレームワーク FastAPI を触ってみた](https://qiita.com/nr81/items/59958ed385b3571d50de)

とにかく早いらしいのですが、特に速度を比較した情報が見当たらなかったので作成しました。

#環境
Windows 10

```
Python 3.6.7 :: Anaconda custom (64-bit)
```

#インストール
###Flask

```
pip install flask
pip install falsk_sqlalchemy
```

###Fast API

```
pip install fastapi
pip install uvicorn
```

#準備
DBと簡単なAPI、APIを叩くコードを書いていきます。
###sqlite db 
DBへの接続を試したいので、SQliteで試してみます。
基本的にはこちらを参考に作成
[python3でsqlite3の操作。作成や読み出しなどの基礎。](https://qiita.com/saira/items/e08c8849cea6c3b5eb0c)

```TEST.db
[(1, 'Taro'), (2, 'Hanako'), (3, 'Hiroki')]
```

###APIを叩くやつ
コメントアウトを入れ替えることでどちらにも対応しています。
FastAPIで通常のGETのように?hoge=fooとして引数を受け取る方式がよくわからなかったので、urlを少し変えています。
特になにもしないAPIと、IDを渡して、username(Hanako)を受け取るAPIを作成しようと思います。
100回APIを実行し、平均時間で速度を比べます。

```call_api.py
import requests
import time

###Flask
URL = 'http://127.0.0.1:5000/'
#Fast API
#URL = 'http://127.0.0.1:8000/'

def main():
	t = []
	for i in range(100):
		start = time.time()
		#say_hello
		url = URL + 'hello'
		res = requests.get(url)
		print(res.text)
		#get_user
		url = URL + 'get_user?user_id=2' #flask
		#url = URL + 'get_user/2' #FastAPI
		res = requests.get(url)
		print(res.text)
		elapsed_time = time.time() - start
		t.append(elapsed_time)
	print(sum(t)/len(t))

if __name__=='__main__':
	main()
```

Flask、FaskApiともにSQLを書かずに済むSQLAlchemyを使用しています。
###Flask
```app.py
from flask import Flask, render_template, request, logging, Response, redirect, flash, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///./TEST.db'
db = SQLAlchemy(app)

class User(db.Model):
	__tablename__ = 'persons'
	id = db.Column(db.Integer, primary_key=True)
	name = db.Column(db.String(80), unique=True)

	def __init__(self, username):
		self.username = username

@app.route('/hello', methods=['GET'])
def say_hello():
	print('hello flask')
	return 'hello'

@app.route('/get_user', methods=['GET'])
def get_user():
	user_id = request.args['user_id']
	username = User.query.get(user_id).name
	return username

if __name__ == '__main__':
    app.run()
```

###FastAPI
[こちら](https://fastapi.tiangolo.com/tutorial/sql-databases/)をコピペしつつ作成しました。

```main.py
from fastapi import FastAPI
from sqlalchemy import Boolean, Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import Session, sessionmaker

app = FastAPI()

SQLALCHEMY_DATABASE_URI = 'sqlite:///./TEST.db'
engine = create_engine(
    SQLALCHEMY_DATABASE_URI, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

class CustomBase:
    # Generate __tablename__ automatically
    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

Base = declarative_base(cls=CustomBase)
Base.metadata.create_all(bind=engine)

db_session = SessionLocal()

class User(Base):
    __tablename__ = 'persons'
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, unique=True, index=True)

@app.get("/hello")
def say_hello():
	print('hello fastapi')
	return 'hello'

@app.get("/get_user/{user_id}")
def read_item(user_id: int):
    print(user_id)
    username = db_session.query(User).get(user_id).name
    return username
```

#実行結果
1行目が何もしないAPI, 2行目がSQLを使うAPI, 3行目が実行時間の平均(秒)です。
###Flask

```
hello
Hanako
0.03350924015045166
```

###FastAPI

```
"hello"
"Hanako"
0.04411268472671509
```

#Conclusion
Flaskの方が若干早いという結果でした。
そんなに公平にコーディングできた感はありませんし、大した処理もしていませんので、Flaskの方が早い！とはいえなさそうですが、
FastAPIの触れ込みの割には大して差はないとは言えるかもしれません。
このままFlaskを利用していこうかと思います。