跳轉到

Go Server Race Condition Patterns

概念概覽

Package-level 變數 Data Race

核心知識

Package-level 變數 Data Race

lastCleanupTimepackage-level time.Time 若在多個 goroutine 中存取,即使只有一個 writer 也會觸發 data race。修復方式: - 改用 atomic.Value 包裝 time.Time - 或用 sync.Mutex 包住所有讀寫操作 - 可用 go test -race 直接驗證

sync.Once 的 Hot-Reload 盲點

sync.Once 建立的 gamedata config index 只會初始化一次,hot-reload 後舊 index 不會失效。需要 hot-reload 支援時,應改用: - 帶版本號的 sync.RWMutex 方案(讀多寫少場景) - config observer pattern,在配置變更時主動重建 index

偵測策略

靜態 JIT 分析(非 runtime)可在 unit/e2e/smoke test 全過的情況下仍發現這類問題,建議納入 CI pipeline。

經驗教訓

  • unit/e2e/smoke test 全通過並不代表沒有 race condition,靜態分析是必要補充

  • sync.Once 適合真正的一次性初始化,不適合需要 invalidation 的 cache 場景

  • go test -race 是驗證 data race 最直接的工具,應加入 CI

常見陷阱

  • package-level time.Time 看似只有一個 goroutine 寫入,但讀取方也需要同步保護

  • sync.Once 用於可變 config 時會造成 stale data,熱更新場景必須換方案

最佳實踐

  • package-level 可變狀態一律用 atomic 或 mutex 保護

  • sync.Once 只用於真正不可變的初始化(如 singleton DB connection)

  • CI 必跑 go test -race

相關概念

相關視角

以下頁面與本概念共享主題,但從不同角度切入。保留獨立視角同時提供交叉參考:

來源 Sessions

日期 Session 貢獻摘要

| 2026-03-17 | 10eef6a0-3a55-4d63-981c-6bc79aff1880 | 識別出 Go 遊戲伺服器中兩類典型 race condition:package-level time.Time 無鎖存取,以及 sync.Once index 在 hot-reload 後不刷新 |


本概念頁面由 Semi-Brain Wiki 系統自動維護

最後更新: 2026-03-17