pythonasyncioapiasyncfastapiframeworkjsonjson-schemaopenapiopenapi3pydanticpython-typespython3redocreststarletteswaggerswagger-uiuvicornweb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
60 lines
1.6 KiB
60 lines
1.6 KiB
import time
|
|
|
|
from fastapi.encoders import jsonable_encoder
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class SubModel(BaseModel):
|
|
name: str
|
|
value: int = 42
|
|
|
|
|
|
class MainModel(BaseModel):
|
|
id: int
|
|
title: str
|
|
sub: SubModel
|
|
items: list[SubModel]
|
|
maybe: str | None = None
|
|
|
|
|
|
def run_benchmark():
|
|
sub = SubModel(name="test")
|
|
model = MainModel(
|
|
id=1,
|
|
title="hello",
|
|
sub=sub,
|
|
items=[sub] * 50, # 50 items to have a decent dictionary size
|
|
)
|
|
|
|
iterations = 20000
|
|
print(f"Benchmarking jsonable_encoder over {iterations} iterations...")
|
|
|
|
# 1. Optimized Path (Direct return)
|
|
# Warmup
|
|
for _ in range(100):
|
|
jsonable_encoder(model)
|
|
|
|
start_time = time.perf_counter()
|
|
for _ in range(iterations):
|
|
jsonable_encoder(model)
|
|
optimized_time = time.perf_counter() - start_time
|
|
|
|
# 2. Original Path (Double serialization via model_dump + recursive dict encoding)
|
|
# Warmup
|
|
for _ in range(100):
|
|
jsonable_encoder(model.model_dump(mode="json"))
|
|
|
|
start_time = time.perf_counter()
|
|
for _ in range(iterations):
|
|
# We simulate the exact old logic: model_dump(mode="json") followed by recursive jsonable_encoder
|
|
obj_dict = model.model_dump(mode="json")
|
|
jsonable_encoder(obj_dict)
|
|
original_time = time.perf_counter() - start_time
|
|
|
|
print(f"Original Code Path: {original_time:.4f} seconds")
|
|
print(f"Optimized Code Path: {optimized_time:.4f} seconds")
|
|
print(f"Speedup: {original_time / optimized_time:.2f}x")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run_benchmark()
|
|
|