Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

開篇詞|想真正學會 Go 併發,建議這樣學

你好,我是晁嶽攀(鳥窩),曾在微博研發平台架構中心擔任資深架構師,也是微服務框架 rpcx 的作者。歡迎來到這份《Go 併發程式設計實戰》學習內容。

這份內容的目標,不只是教你「會用 goroutine / channel」,而是幫你建立一套可以在實務專案裡穩定解題的併發思維。

為什麼要學 Go 併發?

我過去長期使用 Java 做專案開發,後來投入 Go,原因很直接:Go 在併發場景的開發體驗和執行效率,真的很有優勢

Go 的特點大致有幾個:

  • 語法相對精簡,程式碼比較容易維護
  • 工具鏈完整,建置與部署方便
  • goroutine 建立成本低,適合處理大量併發任務
  • channel 讓 goroutine 之間的資料傳遞更直觀

你可以很快寫出一個會動的併發程式,但要寫得穩、寫得準、寫得不踩坑,就是另一回事了。

多數人學 Go 併發時,常卡住的地方

我把常見問題整理成 5 類:

  1. 不知道該選哪一種併發原語(例如 MutexchannelWaitGroup)。
  2. 好幾種做法都能解,卻不知道哪個才是比較好的解法。
  3. 不知道怎麼做任務編排,導致流程順序失控。
  4. 程式會 panic、死鎖(deadlock)或卡住,但很難除錯。
  5. 現成原語不夠用時,程式越寫越複雜、可讀性越差。

這些問題很正常,幾乎每個開始深入學 Go 的工程師都會遇到。

這份內容的學習方式:兩條主線

我建議用「兩條主線」來學,才不會變成零散記憶。

1) 知識主線(你要有哪些工具)

課程核心分成 5 個模組:

  1. 基本併發原語
    • MutexRWMutexWaitGroupCondPoolContext
  2. 原子操作(atomic)
    • 併發原語的基礎能力,理解後更容易看懂底層設計
  3. Channel
    • Go 特有的資料傳遞機制,也是任務編排的核心工具之一
  4. 擴充併發原語
    • 例如信號量(Semaphore)、singleflight、循環柵欄(CyclicBarrier)、errgroup
  5. 分散式併發原語
    • 例如 Leader 選舉、分散式鎖、分散式佇列等

你可以把它想成「武器庫」:工具越完整,面對不同併發情境時越不容易硬解。

2) 學習主線(每個工具要學到什麼程度)

每個模組都建議用同一套節奏學習:

  1. 基本用法
  2. 實作原理
  3. 常見踩坑情境
  4. 真實專案中的錯誤案例(Bug)

這樣學的好處是:你不只知道 API 怎麼呼叫,也知道它為什麼會壞、壞在哪裡、怎麼避開。

學習地圖(先建立全局觀)

                Go 併發程式設計學習地圖

        +--------------------+      +--------------------+
        |      知識主線       |      |      學習主線       |
        | (你要有的工具庫)    |      | (每個工具怎麼學)    |
        +--------------------+      +--------------------+
                  |                             |
                  v                             v
   +--------------------------------+   +------------------+
   | 基本原語 / atomic / channel /  |   | 用法             |
   | 擴充原語 / 分散式原語          |   | 原理             |
   +--------------------------------+   | 易錯情境         |
                  |                     | 真實 Bug 案例    |
                  +----------+----------+------------------+
                             |
                             v
                 +---------------------------+
                 | 實務上能選對工具、避開坑洞 |
                 +---------------------------+

實務上怎麼選工具?先用這個原則

剛開始學時,可以先用這個簡化判斷:

  • 任務編排:優先考慮 channel
  • 共享資源保護:優先考慮傳統同步原語(例如 Mutex

但這只是入門準則,不是萬用答案。

同一個問題,常常有不只一種可行方案;真正的關鍵是:

  • 原語的底層機制是什麼
  • 成本在哪裡(效能、複雜度、可維護性)
  • 哪些情境容易出錯

所以,不建議「什麼都用 channel」;能不能用是一回事,適不適合是另一回事。

為什麼要看原始碼與真實 Bug?

如果你只停在 API 用法,遇到邊界情況通常會很痛苦。

深入看 Go 併發原語的原始碼,你會學到很多實戰價值很高的設計,例如:

  • Mutex 在公平性與效能上的取捨
  • sync.Map 為了提升效能做的資料結構設計
  • 各種異常狀況(panic、競態、死鎖)是怎麼被觸發的

而真實專案的 Bug 案例更重要,因為它能幫你建立「避坑清單」。

最後的目標:不只會用,還能組合與設計

學到後面,你的能力應該分成 3 個層次:

  1. 會用:知道常見併發原語的用途與基本寫法。
  2. 會選:面對情境能選出更合適的做法,避免誤用。
  3. 會設計:能組合既有原語,甚至設計新的併發解法。

能力進階示意

[會用 API] -> [看懂原理與限制] -> [選對工具] -> [組合/設計新原語]
    初學            進階              實務穩定            高階

例如:

  • 你可以把多個原語組合成新的控制流程(例如限制併發數量 + 等待全部完成)
  • 也可以依照需求設計出標準庫沒有直接提供的解法

建議你怎麼讀這份內容

  • 想補基礎:從「基本併發原語」開始
  • channel 不熟:先讀 Channel 相關章節
  • 已熟悉標準庫:可先看「擴充併發原語」與「分散式併發原語」
  • 想快速提升實戰能力:優先看每章的「易錯情境」與「真實 Bug」

結語

Go 併發世界很大,工具也很多。真正的差別不在於你背了多少 API,而在於:

  • 你是否能理解原理
  • 你是否能選對工具
  • 你是否能在複雜場景裡穩定解題

把這份內容當成你的練功地圖,循序建立工具庫、補齊原理、累積避坑經驗,你的 Go 併發能力會進步得很快。

如果你是和同事、朋友一起學,效果通常更好,因為很多併發問題非常適合透過 code review 和討論來釐清。