本文 AI 產出,尚未審核
FastAPI — 應用結構與啟動方式(Application Setup)
使用 python -m uvicorn vs CLI 模式差異
簡介
在開發與部署 FastAPI 應用時,伺服器的啟動方式往往是第一個需要決定的問題。
Uvicorn 作為 FastAPI 官方推薦的 ASGI 伺服器,提供兩種常見的啟動手法:
- 直接在終端機執行
uvicorn指令(CLI 模式) - 以
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-level與workers,指令列只留下必要參數,保持指令簡潔。
範例 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] 已內建)。 |
最佳實踐:
- 開發階段:使用
uvicorn app.main:app --reload(CLI)或python -m uvicorn app.main:app --reload,視環境決定。 - 測試自動化:寫一個
run_server.py,在測試腳本中呼叫uvicorn.run(),保持程式碼一致性。 - Docker 部署:統一採用
python -m uvicorn,並將log-level、workers交給環境變數管理。 - 生產環境:考慮使用
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提供 CLI 與 module (python -m uvicorn) 兩種啟動方式,功能上相同,但在 環境一致性、PATH 依賴與容器化部署 上有微妙差異。- 開發階段 建議使用
--reload並視環境選擇 CLI 或-m,確保快速迭代。 - Docker 與 CI/CD 中,
python -m uvicorn是最安全、最不易出錯的選擇,配合環境變數即可管理日誌與工作執行緒。 - 生產環境 應關閉自動重載,改以多工作執行緒或
gunicorn搭配UvicornWorker的方式提升效能與穩定性。
掌握這些差異與最佳實踐,能讓你的 FastAPI 專案在 開發、測試、部署 各階段都保持一致、可預測,進而提升開發效率與服務可靠度。祝你開發順利,服務常上線!