自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

FastAPI性能對比:同步vs異步

開發(fā) 前端
如果你的應用程序需要處理大量并發(fā)用戶,并嚴重依賴于I/O綁定任務,那么異步FastAPI可以提供更好的性能、可擴展性和響應能力。

FastAPI已成為構建Python API的最流行框架之一,因其速度和易用性而廣受歡迎。但在構建高性能應用程序時,有一個重要問題需要回答:應該使用同步(sync)還是異步(async)代碼執(zhí)行?

在本文中,我們將通過現(xiàn)實世界的性能測試,對同步和異步的FastAPI實現(xiàn)進行基準測試,并深入分析相關數(shù)據(jù),以幫助開發(fā)者決定何時使用這兩種方法。

一、同步與異步在FastAPI中的區(qū)別是什么?

  • 同步代碼(sync):在同步執(zhí)行中,任務一個接一個地處理。每個請求都需要等待前一個請求完成,這在用戶數(shù)量較多或存在慢I/O操作(如數(shù)據(jù)庫查詢或文件上傳)時,可能會導致瓶頸。
  • 異步代碼(async):異步執(zhí)行支持多個請求并發(fā)處理。應用程序無需等待I/O操作(如數(shù)據(jù)庫調用)完成,而是可以繼續(xù)處理其他請求,從而在高并發(fā)環(huán)境中更有效率。

那么,這兩者在性能上的真實差異是什么呢?讓我們來看看。

二、設置:在FastAPI中基準測試同步與異步

為了比較同步和異步實現(xiàn),在這里創(chuàng)建了兩個版本的FastAPI應用程序。

  1. 同步版本:使用傳統(tǒng)的阻塞數(shù)據(jù)庫查詢,采用psycopg2。
  2. 異步版本:使用非阻塞的異步查詢,采用asyncpg。

這兩個版本都執(zhí)行一個簡單的任務:從PostgreSQL數(shù)據(jù)庫查詢用戶。數(shù)據(jù)庫中包含極少的數(shù)據(jù),以便隔離同步/異步機制的影響。

技術棧:

  • 使用FastAPI作為API框架。
  • 使用SQLAlchemy作為ORM。
  • 使用psycopg2或psycopg2-binary(同步)和asyncpg(異步)進行數(shù)據(jù)庫連接。
  • 使用PostgreSQL作為數(shù)據(jù)庫。

為了測試性能,使用**Apache Benchmark(ab)**模擬了1000個請求,具有100個并發(fā)連接。

2.1 同步版本代碼 ??

在同步版本中,在這里使用psycopg2驅動與SQLAlchemy,后者可執(zhí)行阻塞查詢。表格是使用同步的SQLAlchemy引擎創(chuàng)建的。

同步:main.py

from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from .database import get_db, User

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: int, db: Session = Depends(get_db)):
    # 同步和阻塞
    user = db.query(User).filter(User.c.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return {"id": user.id, "name": user.name, "email": user.email}

同步:database.py

from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "postgresql://user:password@localhost/db_name"

# 創(chuàng)建同步的SQLAlchemy引擎
engine = create_engine(DATABASE_URL, echo=True)

# 創(chuàng)建用于同步查詢的會話生成器
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)

# 定義元數(shù)據(jù)
metadata = MetaData()

# 定義User表
User = Table(
    "users", metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String),
    Column("email", String),
)

# 在數(shù)據(jù)庫中創(chuàng)建表
metadata.create_all(engine)

# 獲取同步數(shù)據(jù)庫會話的依賴
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

2.2 異步版本代碼 ??

在異步版本中,在這里使用asyncpg驅動與SQLAlchemy,進行非阻塞查詢。然而,表的創(chuàng)建仍然是同步進行的,因為SQLAlchemy的metadata.create_all()不支持異步。

異步:main.py

from contextlib import asynccontextmanager
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from .database import get_async_db, User, initialize_database


@asynccontextmanager
async def lifespan(app: FastAPI):
    # 啟動:初始化數(shù)據(jù)庫
    await initialize_database()
    yield


app = FastAPI(lifespan=lifespan)


@app.get("/users/{user_id}")
async def get_user(user_id: int, db: AsyncSession = Depends(get_async_db)):
    result = await db.execute(select(User).where(User.c.id == user_id))
    user = result.fetchone()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return {"id": user.id, "name": user.name, "email": user.email}

異步:database.py

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy import MetaData, Table, Column, Integer, String

DATABASE_URL = "postgresql+asyncpg://user:password@localhost/db_name"

# 用于異步查詢的異步引擎
engine = create_async_engine(
    DATABASE_URL,
    echo=True,
    pool_size=10,
    max_overflow=20,
)

# 用于異步查詢的異步會話
AsyncSessionLocal = sessionmaker(
    bind=engine, class_=AsyncSession, expire_on_commit=False
)

# 定義元數(shù)據(jù)
metadata = MetaData()

# 定義User表
users = Table(
    "users",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String),
    Column("email", String),
)


# 創(chuàng)建所有表
async def init_db():
    async with engine.begin() as conn:
        await conn.run_sync(metadata.create_all)


# 獲取異步數(shù)據(jù)庫會話的依賴
async def get_async_db():
    async with AsyncSessionLocal() as session:
        yield session

# 啟動:初始化數(shù)據(jù)庫
async def initialize_database():
    await init_db()

在這個版本中,請求是以異步方式處理的,支持多個請求在等待I/O時并發(fā)處理。

三、基準測試命令

  1. 同步版本:ab -n 1000 -c 100 http://127.0.0.1:8000/users/1
  2. 異步版本:ab -n 1000 -c 100 http://127.0.0.1:8001/users/1

基準測試結果:同步vs異步

以下是基準測試的性能指標分析。

基準測試結果:同步vs異步(Airtable)

性能明細

  1. 每秒請求數(shù):

異步版本每秒可處理50.68個請求,而同步版本每秒只能處理36.89個請求。

在相同時間內,異步處理的請求數(shù)比同步版本多37%,因此在并發(fā)性方面,異步顯然勝出。

  1. 每個請求的響應時間(平均值):

異步版本的平均響應時間低于同步版本27%(1973毫秒vs2710毫秒),這表明在高負載情況下,異步處理請求的效率更高。

  1. 最長請求時間:

兩個版本的最長請求時間相似(約4000毫秒),但異步版本的表現(xiàn)更穩(wěn)定,這體現(xiàn)在響應時間的波動較小。

圖表比較

圖表比較

以上是同步和異步版本在不同百分位數(shù)下的比較圖,包括平均和最長請求時間。

  • 實線表示不同百分位數(shù)下的響應時間。
  • 虛線表示同步(2710.648毫秒)和異步(1973.057毫秒)的平均響應時間。
  • 點線突出顯示同步(4167毫秒)和異步(3851毫秒)的最長請求時間。

四、何時在FastAPI中使用同步與異步?

使用異步的情況:

  • 應用程序需要處理高流量和大量并發(fā)用戶。
  • 應用程序是與I/O綁定的,需要進行大量數(shù)據(jù)庫查詢或API調用。
  • 需要為大量請求最小化響應時間。

使用同步的情況:

  • 應用程序的并發(fā)量較小,或主要執(zhí)行CPU密集型任務。
  • 希望保持代碼庫的簡單性,避免異步處理的復雜性。
  • 不希望應用程序擴展到同時處理數(shù)百或數(shù)千個請求。

五、優(yōu)化異步性能

雖然異步在這些測試中速度更快,但仍有一些方法可以進一步優(yōu)化。

  • 連接池:使用連接池重用數(shù)據(jù)庫連接,避免為每個請求創(chuàng)建一個新連接。
  • 使用異步庫:確保所有I/O綁定的任務(例如文件讀/寫、外部API調用)都以異步方式處理,以獲得最佳性能。
  • 測試更高的并發(fā)性:進行更高并發(fā)量的負載測試(例如,500+用戶),以充分發(fā)揮異步的優(yōu)勢。
engine = create_async_engine(
    DATABASE_URL,
    pool_size=10,
    max_overflow=20
)

六、結論

如果你的應用程序需要處理大量并發(fā)用戶,并嚴重依賴于I/O綁定任務,那么異步FastAPI可以提供更好的性能、可擴展性和響應能力。不過,對于更簡單的用例,可以選擇同步實現(xiàn)。

責任編輯:武曉燕 來源: Python學研大本營
相關推薦

2023-11-27 00:46:39

裸機虛擬機

2017-11-02 13:20:08

數(shù)據(jù)處理PythonNumpy

2021-05-07 17:46:53

存儲IO

2019-12-25 09:53:01

虛擬機技術固態(tài)硬盤

2024-07-11 16:49:43

同步通信異步通信通信

2010-01-22 11:06:03

GNUkFreeBSDLinux

2022-12-05 17:01:20

MySQL數(shù)據(jù)庫Oracle

2010-01-16 11:02:12

Ubuntu性能測試

2017-04-13 15:15:17

Netflix ZuuNginx性能

2010-06-28 13:11:05

2009-03-12 09:59:43

Windows7WindowsVistWindowsXP

2009-07-24 13:17:43

世紀互聯(lián)至強CloudEx

2010-04-13 17:47:50

WindowsEmbe微軟嵌入式開發(fā)Windows7

2010-04-13 17:07:18

WindowsEmbe微軟嵌入式開發(fā)Windows7

2010-04-13 17:28:09

WindowsEmbe微軟嵌入式開發(fā)Windows7

2010-04-13 17:38:13

WindowsEmbe微軟嵌入式開發(fā)Windows7

2009-11-20 09:01:13

Ubuntu性能對比

2017-11-20 13:54:55

FlinkStorm框架

2010-03-15 14:01:26

JavaScript

2017-11-21 15:50:09

FlinkStorm性能
點贊
收藏

51CTO技術棧公眾號