Skip to content

Commit ad43918

Browse files
Add FastAPI HTTP request benchmark (#440)
1 parent 4494463 commit ad43918

File tree

4 files changed

+109
-0
lines changed

4 files changed

+109
-0
lines changed

pyperformance/data-files/benchmarks/MANIFEST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ django_template <local>
4242
dulwich_log <local>
4343
docutils <local>
4444
fannkuch <local>
45+
fastapi <local>
4546
float <local>
4647
genshi <local>
4748
go <local>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[project]
2+
name = "pyperformance_bm_fastapi"
3+
requires-python = ">=3.10"
4+
dependencies = [
5+
"pyperf",
6+
"fastapi",
7+
"uvicorn",
8+
"httpx",
9+
]
10+
urls = {repository = "https://github.com/python/pyperformance"}
11+
dynamic = ["version"]
12+
13+
[tool.pyperformance]
14+
name = "fastapi"
15+
tags = "apps"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fastapi==0.121.0
2+
httpx==0.28.1
3+
uvicorn==0.38.0
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
Test the performance of simple HTTP serving with FastAPI.
3+
4+
This benchmark tests FastAPI's request handling, including:
5+
- Path parameter extraction and validation
6+
- Pydantic model serialization
7+
- JSON response encoding
8+
9+
The bench serves a REST API endpoint that returns JSON objects,
10+
simulating a typical web application scenario.
11+
12+
Author: Savannah Ostrowski
13+
"""
14+
15+
import asyncio
16+
import socket
17+
18+
import httpx
19+
import pyperf
20+
import threading
21+
import uvicorn
22+
from fastapi import FastAPI
23+
from pydantic import BaseModel
24+
25+
HOST = "127.0.0.1"
26+
27+
CONCURRENCY = 150
28+
29+
class Item(BaseModel):
30+
id: int
31+
name: str
32+
price: float
33+
tags: list[str] = []
34+
35+
app = FastAPI()
36+
37+
@app.get("/items/{item_id}", response_model=Item)
38+
async def get_item(item_id: int):
39+
return {
40+
"id": item_id,
41+
"name": "Sample Item",
42+
"price": 9.99,
43+
"tags": ["sample", "item", "fastapi"]
44+
}
45+
46+
def setup_server():
47+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
48+
s.bind((HOST, 0))
49+
s.listen(1)
50+
port = s.getsockname()[1]
51+
52+
config = uvicorn.Config(app, host=HOST, port=port, log_level="error")
53+
server = uvicorn.Server(config)
54+
55+
server_thread = threading.Thread(target=server.run, daemon=True)
56+
server_thread.start()
57+
58+
while not server.started:
59+
pass
60+
61+
url = f"http://{HOST}:{port}"
62+
return url
63+
64+
def bench_fastapi(loops, url):
65+
async def run_benchmark():
66+
async with httpx.AsyncClient() as client:
67+
t0 = pyperf.perf_counter()
68+
69+
for i in range(loops):
70+
tasks = [
71+
client.get(f"{url}/items/{i}")
72+
for _ in range(CONCURRENCY)
73+
]
74+
responses = await asyncio.gather(*tasks)
75+
for response in responses:
76+
response.raise_for_status()
77+
data = response.json()
78+
assert data["id"] == i
79+
assert "tags" in data
80+
81+
return pyperf.perf_counter() - t0
82+
83+
return asyncio.run(run_benchmark())
84+
85+
86+
if __name__ == "__main__":
87+
url = setup_server()
88+
runner = pyperf.Runner()
89+
runner.metadata['description'] = "Test the performance of HTTP requests with FastAPI"
90+
runner.bench_time_func("fastapi_http", bench_fastapi, url)

0 commit comments

Comments
 (0)