이 글은 하이퍼 커넥트의 Pydantic은 아주 느리다. 불필요한 곳에서 가급적 사용하지 말자#5글을 참고하여 작성하였습니다.
Pydantic은 FastAPI에서 사용하는 데이터 검증과 parsing 라이브러리입니다.
아래 처럼 사용이 가능합니다.
from datetime import date
from pydantic import BaseModel
class User(BaseModel):
user_id: int
birthday: date
User.model_validate_json('{"user_id": "100", "birthday": "2000-01-01"}')
FastAPI는 내부적으로 Pydantic을 포함하고 있고, API request 변수와 response type을 Pydantic 객체로 넣어주면 Swagger UI 까지 자동으로 만들어주고 있습니다. 그만큼 FastAPI를 사용한다면 Pydantic은 필수적으로 알아야합니다.
Pydantic은 정말 편리하지만 data validation이 필요 없는 환경에서도 Pydantic을 남발해서는 안됩니다. 검증 및 parsing에 드는 시간이 많이 소요되기 때문입니다.
Pydantic의 속도를 보기전 하나 짚어야할 점은 Pydantic이 V1에서 V2로 바뀌면서 내부가 Rust구현으로 바뀌고 내장기능도 일부 바뀌었다는 것입니다. 하이퍼 커넥트의 블로그는 1 버전에서 실행한 결과인데 현재 2 버전으로 바뀌었는데 성능차이는 어떨까요?
import timeit
from typing import List
from pydantic import BaseModel
class FeatureSet(BaseModel):
user_id: int
features: List[float]
def create_pydantic_instances() -> None:
for i in range(400):
obj = FeatureSet(
user_id=i,
features=[1.0 * i + j for j in range(50)],
)
elapsed_time = timeit.timeit(create_pydantic_instances, number=1)
print(f"pydantic: {elapsed_time * 1000:.2f}ms")
# pydantic: 2.22ms
v1에서는 12ms가량 소요됐는데 v2는 2ms밖에 걸리지 않습니다.
import timeit
from typing import List
class FeatureSet:
def __init__(self, user_id: int, features: List[float]) -> None:
self.user_id = user_id
self.features = features
def create_class_instances() -> None:
for i in range(400):
obj = FeatureSet(
user_id=i,
features=[1.0 * i + j for j in range(50)],
)
elapsed_time = timeit.timeit(create_class_instances, number=1)
print(f"class: {elapsed_time * 1000:.2f}ms")
# class: 1.14ms
그래도 기본 class로 생성하는게 2배정도 빠르네요.