Python ASGI Web框架性能基准比较

性能基准测试报告:MicroPie、FastAPI、Starlette、Quart、LiteStar

Python ASGI(Asynchronous Server Gateway Interface)框架是一种用于构建异步网络应用程序的框架,它是 WSGI(Web Server Gateway Interface)的异步版本。

本报告对四个 Python ASGI 框架进行了详细的性能比较:MicroPie、FastAPI、LiteStar、Starlette和 Quart。进行基准测试是为了评估它们在不同工作负载下处理高并发性的能力。

已测试的框架:

  • MicroPie - “一款超微型 ASGI Python Web 框架,让您不再受束缚”
  • FastAPI -“用于构建 API 的现代、快速(高性能)Web 框架”
  • Starlette -“轻量级的 ASGI 框架 / 工具包,非常适合用 Python 构建异步 Web 服务”
  • Quart - “流行的 Flask 微框架 API 的 asyncio 重新实现”
  • LiteStar—— “轻松构建高性能 API”

测试场景:

  • / (基本 JSON 响应)测量基线请求处理性能。
  • /compute (CPU 密集型工作负载):模拟计算负载。
  • /delayed (I/O 绑定工作负载):通过人为延迟模拟异步任务。

测试环境:

  • CPU: Star Labs StarLite Mk IV
  • 服务器: Uvicorn(4 名工作人员)
  • 基准测试工具: wrk
  • 测试时长:每个端点 30 秒
  • 连接数: 1000 个并发连接
  • 主题: 4

基准测试结果
总体表现摘要

框架    / 请求数/秒    延迟(毫秒)    传输/秒  /compute 请求数/秒  延迟(毫秒) 传输/秒 /delayed 请求数/秒 延迟(毫秒)  传输/秒
Quart    1,790.77    550.98ms    824.01 KB    1,087.58    900.84ms    157.35 KB    1,745.00    563.26ms    262.82 KB
FastAPI    2,398.27    411.76ms    1.08 MB    1,125.05    872.02ms    162.76 KB    2,017.15    488.75ms    303.78 KB
MicroPie    2,583.53    383.03ms    1.21 MB    1,172.31    834.71ms    191.35 KB    2,427.21    407.63ms    410.36 KB
Starlette    2,876.03    344.06ms    1.29 MB    1,150.61    854.00ms    166.49 KB    2,575.46    383.92ms    387.81 KB
Litestar    2,079.03    477.54ms    308.72 KB    1,037.39    922.52ms    150.01 KB    1,718.00    581.45ms    258.73 KB

结论:

  1. Starlette 的整体表现最佳——在所有测试中速度最快,尤其在异步工作负载方面表现出色。
  2. MicroPie 与 Starlette 非常接近——具有强大的 CPU 和异步性能,使其成为一种出色的轻量级替代品。
  3. FastAPI 在计算负载下会变慢——性能受到验证开销的影响。
  4. Quart 是最慢的——在所有场景中延迟最高,每秒请求数最低。
  5. Litestar 在整体性能上落后——与 MicroPie 和 Starlette 相比,延迟更高、吞吐量更低。
  6. Litestar 并未针对高并发进行很好的优化——与其他 ASGI 框架相比,计算密集型任务和异步任务的速度都很慢。

测试代码:
MicroPie (micro.py)

import orjson, asyncio
from MicroPie import Server

class Root(Server):
    async def index(self):
        return 200, orjson.dumps({"message": "Hello, World!"}), [("Content-Type", "application/json")]

    async def compute(self):
        return 200, orjson.dumps({
"result": sum(i * i for i in range(10000))}), [("Content-Type", "application/json")]

    async def delayed(self):
        await asyncio.sleep(0.01)
        return 200, orjson.dumps({
"status": "delayed response"}), [("Content-Type", "application/json")]

app = Root()
LiteStar (lites.py)
from litestar import Litestar, get
import asyncio
import orjson
from litestar.response import Response

u/get(
"/")
async def index() -> Response:
    return Response(content=orjson.dumps({
"message": "Hello, World!"}), media_type="application/json")

u/get(
"/compute")
async def compute() -> Response:
    return Response(content=orjson.dumps({
"result": sum(i * i for i in range(10000))}), media_type="application/json")

@get(
"/delayed")
async def delayed() -> Response:
    await asyncio.sleep(0.01)
    return Response(content=orjson.dumps({
"status": "delayed response"}), media_type="application/json")

app = Litestar(route_handlers=[index, compute, delayed])

FastAPI (fast.py)

from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
import asyncio

app = FastAPI()

@app.get("/", response_class=ORJSONResponse)
async def index():
    return {
"message": "Hello, World!"}

@app.get(
"/compute", response_class=ORJSONResponse)
async def compute():
    return {
"result": sum(i * i for i in range(10000))}

@app.get(
"/delayed", response_class=ORJSONResponse)
async def delayed():
    await asyncio.sleep(0.01)
    return {
"status": "delayed response"}

Starlette (star.py)

from starlette.applications import Starlette
from starlette.responses import Response
from starlette.routing import Route
import orjson, asyncio

async def index(request):
    return Response(orjson.dumps({"message": "Hello, World!"}), media_type="application/json")

async def compute(request):
    return Response(orjson.dumps({
"result": sum(i * i for i in range(10000))}), media_type="application/json")

async def delayed(request):
    await asyncio.sleep(0.01)
    return Response(orjson.dumps({
"status": "delayed response"}), media_type="application/json")

app = Starlette(routes=[Route(
"/", index), Route("/compute", compute), Route("/delayed", delayed)])

Quart (qurt.py)

from quart import Quart, Response
import orjson, asyncio

app = Quart(<strong>name</strong>)

@app.route("/")
async def index():
    return Response(orjson.dumps({
"message": "Hello, World!"}), content_type="application/json")

@app.route(
"/compute")
async def compute():
    return Response(orjson.dumps({
"result": sum(i * i for i in range(10000))}), content_type="application/json")

@app.route(
"/delayed")
async def delayed():
    await asyncio.sleep(0.01)
    return Response(orjson.dumps({
"status": "delayed response"}), content_type="application/json")

性能测试方法Benchmarking
wrk -t4 -c1000 -d30s http://127.0.0.1:8000/
wrk -t4 -c1000 -d30s http://127.0.0.1:8000/compute
wrk -t4 -c1000 -d30s http://127.0.0.1:8000/delayed

结论

  • Starlette 是高性能应用程序的最佳选择。
  • MicroPie 以更简单的架构提供近乎相同的性能。
  • FastAPI 非常适合 API 开发,但却存在验证开销的问题。
  • Quart 并不适合高并发工作负载。
  • Litestar 还有改进空间——其较高的延迟和较低的请求率表明它可能不是高度并发应用程序的最佳选择