Like Share Discussion Bookmark Smile

J.J. Huang   2025-07-02   Getting Started Golang 07.套件   瀏覽次數:次   DMCA.com Protection Status

Go | 同步套件的函式與介紹

💬 簡介

在 Go 語言的並行模型中,goroutine 讓多工變得簡單,但也因此帶來了資源競爭與資料一致性的問題。

Go 標準函式庫中的 sync 套件,提供了處理這些問題的常用工具,包括互斥鎖(Mutex)、等待組(WaitGroup)、一次性執行(Once)等,協助我們安全地同步資料與協調多個 goroutine 的行為。

本篇將介紹 sync 套件中的核心型別與應用方式,幫助你建立穩固的併發控制基礎。

圖片來源:Gophers


💡 套件匯入與常用結構

1
import "sync"
型別 說明
sync.Mutex 互斥鎖,防止多個 goroutine 同時操作資源
sync.RWMutex 讀寫鎖,支援多讀單寫
sync.WaitGroup 等待組,用來等待 goroutine 完成
sync.Once 僅執行一次的初始化程式
sync.Map 並發安全的 map 結構
sync.Cond 條件變數,用於 goroutine 間通知與等待

🔒 互斥鎖:sync.Mutex

用來保護資源,避免同時存取造成錯誤。

1
2
3
4
5
6
var mu sync.Mutex
count := 0

mu.Lock()
count++
mu.Unlock()

搭配 goroutine 使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var (
mu sync.Mutex
count int
)

func worker() {
mu.Lock()
defer mu.Unlock()
count++
}

func main() {
for i := 0; i < 10; i++ {
go worker()
}

time.Sleep(time.Second)
fmt.Println("Final count:", count)
}

📚 等待組:sync.WaitGroup

等候一組 goroutine 全部結束再繼續執行。

1
2
3
4
5
6
7
8
9
10
11
12
13
var wg sync.WaitGroup

for i := 0; i < 5; i++ {
wg.Add(1)

go func(id int) {
defer wg.Done()
fmt.Printf("Worker %d done\n", id)
}(i)
}

wg.Wait()
fmt.Println("All workers finished")
  • Add(n):增加等待數量。
  • Done():表示單一任務完成。
  • Wait():阻塞直到所有任務完成。

🧠 一次性執行:sync.Once

確保某個初始化動作只執行一次,常見於全域變數初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var once sync.Once

func initResource() {
fmt.Println("Initializing resource")
}

func main() {
for i := 0; i < 3; i++ {
go func() {
once.Do(initResource)
}()
}

time.Sleep(time.Second)
}

即使呼叫三次 Do()initResource() 也只會執行一次。


🗺️ 並發安全 Map:sync.Map

sync.Map 是內建支援多 goroutine 存取的 map,無需額外加鎖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var m sync.Map

m.Store("name", "gopher")
m.Store("age", 5)

value, ok := m.Load("name")
if ok {
fmt.Println("Name:", value)
}

m.Range(func(k, v any) bool {
fmt.Println(k, "=>", v)
return true
})

適合讀多寫少的場景,也適合需要共享狀態的並行系統。


📎 讀寫鎖:sync.RWMutex

允許多個讀者同時讀,但只允許一個寫者寫。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var rw sync.RWMutex
var shared int

func reader() {
rw.RLock()
fmt.Println("Read:", shared)
rw.RUnlock()
}

func writer() {
rw.Lock()
shared++
rw.Unlock()
}

RLock()RUnlock() 為讀鎖
Lock()Unlock() 為寫鎖


🔔 條件變數:sync.Cond(進階應用)

配合 Mutex 使用,讓 goroutine 等待特定條件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var (
mu sync.Mutex
cond = sync.NewCond(&mu)
ready = false
)

func waitForReady() {
cond.L.Lock()
for !ready {
cond.Wait()
}
fmt.Println("Condition met!")
cond.L.Unlock()
}

func main() {
go waitForReady()

time.Sleep(1 * time.Second)
cond.L.Lock()
ready = true
cond.Signal()
cond.L.Unlock()
}

常用於生產者與消費者模型的同步控制。


⚠️ 注意事項

  • 所有鎖具(Mutex、RWMutex)必須成對使用 Lock/Unlock。
  • sync.Map 適用於場景複雜或動態鍵值存取頻繁,若場景簡單仍建議使用 map+mutex。
  • sync.Once 僅能保證「一次性」,不能重複觸發。

🎯 總結

Go 的 sync 套件提供:

  • ✅ 多 goroutine 間安全存取共享資源的基礎工具
  • ✅ 明確、簡單的 API 接口設計
  • ✅ 可支援 WaitGroup 與 Once 等協調控制情境
  • ✅ 搭配 sync.Map 快速建構併發容器

透過這些工具,你可以構建出穩定、安全且效能良好的並行程式,這是 Go 語言併發模型的核心基礎之一!

最後建議回顧一下 Go | 菜鳥教學 目錄,了解其章節內容。


註:以上參考了
Go