🎯 什麼情境該想到我
當你在 Go 裡處理並行,手很癢想用鎖去保護一個共享變數的時候。
「不要透過共享記憶體來通訊;要透過通訊來共享記憶體。」
⚙️ 怎麼用(步驟 / 公式)
1. 心智模型:值在 channel 上傳遞,不被多方同時持有
Go 鼓勵的做法是把值放上 channel 傳來傳去,而不是讓多個執行緒主動共享它。
任何時刻只有一個 goroutine 能存取那個值 → 資料競爭在設計上就不可能發生。
2. 原文給的直覺(很好用)
想像一個單執行緒程式跑在一顆 CPU 上——它不需要同步。
再跑一個實例——它也不需要同步。
現在讓這兩個互相通訊——如果通訊本身就是同步機制,那就仍然不需要其他同步。
Unix pipeline 完美符合這個模型。Go 的並行源自 Hoare 的 CSP,也可以看成是型別安全版的 Unix pipe。
3. goroutine 的成本模型
就是一個「與其他 goroutine 併行執行的函式」。輕量,成本略高於配置堆疊空間;堆疊從小開始、按需增長。它們被多工到多個 OS 執行緒上,所以其中一個因 I/O 阻塞時,其他照跑。
go list.Sort() // 併行跑,不等它函式字面量在 Go 裡是閉包,實作會確保被引用的變數活得夠久。
4. ⭐ 但這句標語有邊界——原文自己講的
“This approach can be taken too far. Reference counts may be best done by putting a mutex around an integer variable, for instance.”
引用計數這種東西,用 mutex 包一個整數就好。 channel 是高階做法,不是所有同步問題的答案。
判準:要傳遞「所有權」或「資料流」用 channel;只是保護一小塊狀態用 mutex。
🧪 我實際套用的紀錄
- 2026-08-28:(待填)
⚠️ 注意 / 什麼時候不適用
- ⚠️ 來源文件的範例寫法已經舊了。觀念沒變,但等待多個 goroutine 完成的寫法變了——現在有
sync.WaitGroup.Go(Go 1.25)與errgroup,不必再手動用 channel 計數。→ Modern Go Guidelines - 原文完全沒有
context,但實務上取消與逾時幾乎都靠它。這是 2009 年文件的最大缺口之一。 - 只記半句標語是常見錯誤。很多人只記「share memory by communicating」,忘了原文緊接著就說這可以做過頭。
- channel 不是免費的:有配置與同步成本,熱路徑上用 mutex 保護一個計數器通常更快也更清楚。
- 從 Java/C++ 帶來的「先加鎖再說」直覺會讓你寫出能跑但不像 Go 的程式;反過來「什麼都塞 channel」也一樣。
🔗 相關工具
- Modern Go Guidelines —— 現代的等待與同步寫法(
WaitGroup.Go、sync.OnceValue、atomic.Pointer[T]) - 工具-線性一致性與共識 —— 跨程序的並行問題;這張是單一程序內的