Go Back

Fastapi Async

2024-06-05

FastAPI 是一個輕量、易於使用的 Python API 框架。

非同步的支持

fastAPI 在 function 上預設會將一般 def function 放在 threadPool 中執行,因此可以同步處理多個 request ,而不會阻塞伺服器。

驗證多種情況

  1. 同步函式 + 同步程式
  2. 非同步函式 + 同步程式
  3. 非同步函式 + 非同步程式

1. 同步函式 + 同步程式

當 client request /ask 時,會需要等待 5 秒才能回傳結果,這時因為 threadPool 的關係,其他的 client 的 request 可以繼續執行。

from fastapi import FastAPI
import uvicorn
import time

app = FastAPI()

def chat(message):
    time.sleep(5)
    return 'handle done:' + message

@app.get("/do_something")
def do_something():
    print('receive a request: do_something')
    return 'handle done: do_something'

@app.post("/ask")
def ask_question(content: str):
    print('receive a request:', content)
    response = chat(content)
    return response

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

輸出結果
用兩個 client 同時呼叫 /ask/do_something
Server

# 1. /ask print
receive a request: call ask
# 2. /do_something print
receive a request: do_something
# /ask waits for 5 seconds ...

Client

# 1. /do_something reutrn result
handle done: do_something
# /ask waits for 5 seconds
# 2. /ask return result
handle done: call ask

2. 非同步函式 + 同步程式

因使用 async def 不會進 threadPool 執行,所以程式中沒有用 await 等待的話,反而會變得比平常還慢。

  • 當 client request /ask 時,會需要等待 5 秒才能回傳結果,這時因為沒有 threadPool 的關係,其他的 client 的 request 無法執行,會等到 /ask 完成才開始執行。
from fastapi import FastAPI
import uvicorn
import time

app = FastAPI()

def chat(message):
    time.sleep(5)
    return 'handle done:' + message

@app.get("/do_something")
async def do_something():
    print('receive a request: do_something')
    return 'handle done: do_something'

@app.post("/ask")
async def ask_question(content: str):
    print('receive a request:', content)
    response = chat(content)
    return response

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

輸出結果
用兩個 client 同時呼叫 /ask/do_something
Server

# 1. /ask print
receive a request: call ask
# /ask waits for 5 seconds ...
# 2. /do_something print
receive a request: do_something

Client

# /ask waits for 5 seconds
# 1. /ask return result
handle done: call ask
# 2. /do_something reutrn result
handle done: do_something

3. 非同步函式 + 非同步程式

當 client request /ask 時,會需要等待 5 秒才能回傳結果,這時因為使用 await 的關係,其他的 client 的 request 可以繼續執行。

from fastapi import FastAPI
import uvicorn
import time
import asyncio

app = FastAPI()

async def chat(message):
    await asyncio.sleep(5)
    return 'handle done:' + message

@app.get("/do_something")
def do_something():
    print('receive a request: do_something')
    return 'handle done: do_something'

@app.post("/ask")
async def ask_question(content: str):
    print('receive a request:', content)
    response = await chat(content)
    return response

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

輸出結果,同第一個範例

結論

若程式有需要使用 await 關鍵字時,再改 async def 就好,單純使用 async def 速度反而會變慢。