本文 AI 產出,尚未審核

FastAPI — 應用結構與啟動方式(Application Setup)

使用 python -m uvicorn vs CLI 模式差異


簡介

在開發與部署 FastAPI 應用時,伺服器的啟動方式往往是第一個需要決定的問題。
Uvicorn 作為 FastAPI 官方推薦的 ASGI 伺服器,提供兩種常見的啟動手法:

  1. 直接在終端機執行 uvicorn 指令(CLI 模式)
  2. python -m uvicorn 方式呼叫模組(module 模式)

雖然兩者最終都會啟動同一個程式,但在 參數傳遞、環境設定、除錯資訊 等細節上有所不同。了解這些差異,能讓我們在本機開發、Docker 化或正式上線時,選擇最合適的方式,避免不必要的錯誤與效能損失。


核心概念

1. 兩種啟動方式的基本語法

方式 範例指令 說明
CLI uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 直接呼叫已安裝於 PATH 中的 uvicorn 可執行檔。
Module python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 透過 Python 的 -m 參數載入 uvicorn 模組,等同於 python -c "import uvicorn; uvicorn.run(...)"

重要:兩者在傳遞參數時的行為相同,但 module 模式 會先載入 Python 的執行環境,再由 uvicorn 作為子模組啟動,這在某些虛擬環境或容器內會更穩定。


2. 為什麼會有 -m 方式?

  • 避免 PATH 問題:在虛擬環境或 Docker 容器中,uvicorn 可執行檔的路徑不一定在 $PATH,使用 python -m uvicorn 可保證呼叫到正確的套件版本。
  • 一致的執行環境-m 會使用當前 python 解譯器,確保與開發時使用的相同(例如 python3.11),減少因版本不一致帶來的錯誤。
  • 支援 -c 直接執行:若想在程式碼中動態決定啟動參數,可寫成 python -c "import uvicorn; uvicorn.run('app.main:app', reload=True)",而 -m 只是一個更簡潔的包裝。

3. 常見參數差異與注意點

參數 CLI 直接使用 -m 模式使用 小技巧
--reload 直接加在指令後 同上 開發時建議加上,會自動偵測程式碼變動並重新載入
--workers 可直接指定多工作執行緒 同上 只在生產環境使用,搭配 --loop uvloop 效能更佳
--log-level --log-level debug 同上 -m 模式下仍支援所有 CLI 參數
環境變數 (UVICORN_...) 直接在終端機設定 export UVICORN_LOG_LEVEL=info 仍可使用 透過環境變數設定較不易被指令列遺漏

提示:在 Dockerfile 中,建議使用 CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"],這樣可以保證容器啟動時使用的 python 解譯器與套件版本一致。


4. 程式碼範例

以下示範 5 個實用範例,說明如何在不同情境下選擇啟動方式。

範例 1️⃣:最簡單的開發啟動(CLI)

uvicorn app.main:app --reload
  • 說明:在本機開發時,只要全域或虛擬環境已安裝 uvicorn,直接使用 CLI 即可。--reload 讓程式碼變更即時生效。

範例 2️⃣:使用 -m 防止 PATH 問題(虛擬環境)

# 假設已啟動 venv
source .venv/bin/activate
python -m uvicorn app.main:app --reload
  • 說明:即使 uvicorn 沒有被加入 $PATH-m 仍會正確呼叫安裝在該虛擬環境的版本。

範例 3️⃣:在 Dockerfile 中使用 -m(最佳實務)

FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
  • 說明CMD 用 JSON 陣列寫法,可避免字串解析錯誤,且保證使用容器內的 python 執行 uvicorn

範例 4️⃣:結合環境變數與 -m(生產環境)

export UVICORN_LOG_LEVEL=info
export UVICORN_WORKERS=4
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000
  • 說明:透過環境變數設定 log-levelworkers,指令列只留下必要參數,保持指令簡潔。

範例 5️⃣:在程式碼內部動態啟動(測試或腳本)

# run_server.py
import uvicorn

if __name__ == "__main__":
    uvicorn.run(
        "app.main:app",
        host="127.0.0.1",
        port=8000,
        reload=True,
        log_level="debug",
    )
python run_server.py
  • 說明:當需要在測試框架或自訂腳本中啟動 FastAPI 時,直接呼叫 uvicorn.run 更靈活,且等效於 python -m uvicorn

常見陷阱與最佳實踐

陷阱 說明 解法
PATH 找不到 uvicorn 在某些 CI/CD pipeline 或 Docker 中,uvicorn 未被加入 $PATH 使用 python -m uvicorn 或在 Dockerfile 中明確指定完整路徑 (/usr/local/bin/uvicorn)。
版本不一致 全域安裝的 uvicorn 版本與虛擬環境不同,導致功能缺失。 永遠 於虛擬環境或容器內安裝,並以 -m 呼叫,以保證使用同一個 Python 解譯器。
--reload 在生產環境 --reload 會持續監控檔案變動,會額外消耗 CPU。 只在開發環境使用,生產環境切換為 --workers + gunicorn(或 uvicorn--workers)。
日誌設定混亂 同時使用 CLI 參數與環境變數設定 log-level,可能產生衝突。 統一使用一種方式,建議在 Docker 中以環境變數管理,CLI 只保留必要參數。
熱重載失效 在 Windows Subsystem for Linux (WSL) 或某些檔案系統上,--reload 可能偵測不到變更。 確認檔案系統支援 inotify,或改用 watchgod 監控(uvicorn[standard] 已內建)。

最佳實踐

  1. 開發階段:使用 uvicorn app.main:app --reload(CLI)或 python -m uvicorn app.main:app --reload,視環境決定。
  2. 測試自動化:寫一個 run_server.py,在測試腳本中呼叫 uvicorn.run(),保持程式碼一致性。
  3. Docker 部署:統一採用 python -m uvicorn,並將 log-levelworkers 交給環境變數管理。
  4. 生產環境:考慮使用 gunicorn -k uvicorn.workers.UvicornWorker app.main:app,或直接使用 uvicorn--workers,但務必關閉 --reload

實際應用場景

場景 推薦啟動方式 為什麼
本機開發 uvicorn app.main:app --reload 快速、直觀,且支援自動重新載入。
多人協作的虛擬環境 python -m uvicorn app.main:app --reload 確保每位開發者使用相同的 Python 解譯器與套件版本。
CI/CD 測試 python -m uvicorn app.main:app --port 8080 & sleep 5 && curl -f http://localhost:8080/health 以背景執行方式啟動,測試後立刻關閉,避免 PATH 問題。
Docker 部署 CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] 保證容器啟動時使用正確的 python,且易於加入環境變數。
高流量生產 gunicorn -k uvicorn.workers.UvicornWorker app.main:app --workers 4(或 uvicorn --workers 4 多工作執行緒提供更好的併發處理,且不需要 --reload

總結

  • uvicorn 提供 CLImodule (python -m uvicorn) 兩種啟動方式,功能上相同,但在 環境一致性、PATH 依賴與容器化部署 上有微妙差異。
  • 開發階段 建議使用 --reload 並視環境選擇 CLI 或 -m,確保快速迭代。
  • Docker 與 CI/CD 中,python -m uvicorn 是最安全、最不易出錯的選擇,配合環境變數即可管理日誌與工作執行緒。
  • 生產環境 應關閉自動重載,改以多工作執行緒或 gunicorn 搭配 UvicornWorker 的方式提升效能與穩定性。

掌握這些差異與最佳實踐,能讓你的 FastAPI 專案在 開發、測試、部署 各階段都保持一致、可預測,進而提升開發效率與服務可靠度。祝你開發順利,服務常上線!