Background
趣味で作成しているサービスのバックエンドの自作APIとしてFlaskを使用していました。
数日前、Qiitaを見ているとこんな記事がありました。
python製の最新APIフレームワーク FastAPI を触ってみた
とにかく早いらしいのですが、特に速度を比較した情報が見当たらなかったので作成しました。
環境
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の操作。作成や読み出しなどの基礎。
[(1, 'Taro'), (2, 'Hanako'), (3, 'Hiroki')]
APIを叩くやつ
コメントアウトを入れ替えることでどちらにも対応しています。
FastAPIで通常のGETのように?hoge=fooとして引数を受け取る方式がよくわからなかったので、urlを少し変えています。
特になにもしないAPIと、IDを渡して、username(Hanako)を受け取るAPIを作成しようと思います。
100回APIを実行し、平均時間で速度を比べます。
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
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
こちらをコピペしつつ作成しました。
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を利用していこうかと思います。