同步原語
Go 語言同步原語:Mutex、WaitGroup、Atomic。
WaitGroups
用於等待所有啟動的 Goroutines 完成。
當你不需要 goroutine 回傳資料時,使用 WaitGroups。
- 是一種同步原語,允許多個 goroutines 互相等待
- 像計數器一樣阻塞執行,直到內部計數器變為 0
- package
sync提供基本同步功能
import "sync"
var wg sync.WaitGroup
wg.Add(int)
wg.Wait()
wg.Done()如果 WaitGroup 明確傳遞給函式,應該使用指標傳遞。
Methods
Add:設定要等待的 goroutines 數量(增加計數器)
- 參數中的整數作為計數器
- 表示要等待的 goroutines 數量
Wait:阻塞執行直到內部計數器減為 0
Done:將
Add()方法的內部計數減 1- 由 goroutine 呼叫以表示它已完成

完整範例
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; 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 completed")
}Mutexes
互斥鎖,用於保護共享資源,確保同一時間只有一個 goroutine 可以存取。
sync.Mutex
type Counter struct {
mu sync.Mutex
value int
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *Counter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}sync.RWMutex
讀寫鎖,允許多個讀取者同時存取,但寫入時獨佔。
| 方法 | 說明 |
|---|---|
RLock() | 獲取讀鎖(可多個同時持有) |
RUnlock() | 釋放讀鎖 |
Lock() | 獲取寫鎖(獨佔) |
Unlock() | 釋放寫鎖 |
type SafeMap struct {
mu sync.RWMutex
data map[string]int
}
func (m *SafeMap) Get(key string) (int, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
val, ok := m.data[key]
return val, ok
}
func (m *SafeMap) Set(key string, value int) {
m.mu.Lock()
defer m.mu.Unlock()
m.data[key] = value
}Atomic Counters
原子計數器,用於無鎖的計數操作,比 Mutex 更輕量。
import "sync/atomic"
var counter int64
// 原子增加
atomic.AddInt64(&counter, 1)
// 原子讀取
value := atomic.LoadInt64(&counter)
// 原子儲存
atomic.StoreInt64(&counter, 100)
// Compare-And-Swap
atomic.CompareAndSwapInt64(&counter, old, new)完整範例
func main() {
var counter int64
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt64(&counter, 1)
}()
}
wg.Wait()
fmt.Println("Counter:", counter) // 1000
}sync.Once
確保函式只執行一次,常用於單例模式或初始化。
var (
instance *Database
once sync.Once
)
func GetInstance() *Database {
once.Do(func() {
instance = &Database{
// 初始化...
}
})
return instance
}sync.Pool
物件池,用於重用臨時物件,減少記憶體分配和 GC 壓力。
var bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func process(data []byte) {
buf := bufferPool.Get().(*bytes.Buffer)
defer func() {
buf.Reset()
bufferPool.Put(buf)
}()
buf.Write(data)
// 處理 buffer...
}sync.Map
並發安全的 map,適用於讀多寫少的場景。
var m sync.Map
// 儲存
m.Store("key", "value")
// 讀取
value, ok := m.Load("key")
// 讀取或儲存(若不存在則儲存)
actual, loaded := m.LoadOrStore("key", "default")
// 刪除
m.Delete("key")
// 遍歷
m.Range(func(key, value interface{}) bool {
fmt.Printf("%v: %v\n", key, value)
return true // 回傳 false 停止遍歷
})對於大多數情況,使用
map + sync.RWMutex 效能更好。sync.Map 適合 key 集合穩定且讀取頻繁的場景。Worker Pools
工作池模式,用於管理並發任務,控制並發數量。
func worker(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
results <- job * 2
}
}
func main() {
const numJobs = 10
const numWorkers = 3
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
// 啟動 workers
for w := 1; w <= numWorkers; w++ {
go worker(w, jobs, results)
}
// 發送任務
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// 收集結果
for r := 1; r <= numJobs; r++ {
<-results
}
}- Links: