Skip to main content

Mutex 互斥鎖

  • 主要有三種鎖,使用情境不太同

sync.Mutex

  • 多個 goroutine 同時去讀寫某個變數會出問題,因此加上 lock,確保前一個 goroutine 操作完,下一個才能用

情境:多人同時存款

package main

import (
"fmt"
"sync"
)

type Bank struct {
balance int // 想成銀行全部餘額
}

// 存款
func (b *Bank) saveMoney(money int) {
b.balance += money
}

// 確認餘額
func (b *Bank) getBalance() int {
return b.balance
}

func main() {
var wg sync.WaitGroup
var mux sync.Mutex

wg.Add(1000)

b := Bank{}

for i := 0; i < 1000; i++ {
go func() {
mux.Lock()
b.saveMoney(1000) // 前後上鎖
mux.Unlock()

wg.Done()
}()
}

wg.Wait()

fmt.Println(b.getBalance())
}

sync.RWMutex

  • 讀寫鎖 (多讀單寫),允許多個讀 concurrency,單個寫
  • 寫的時候 lock,確保值是對的,讀的時候 concurrency

情境:既然可以多人同時存,那也要能多人同時讀

package main

import (
"fmt"
"sync"
)

type Bank struct {
balance int
}

// 存款
func (b *Bank) saveMoney(money int) {
b.balance += money
}

// 確認餘額
func (b *Bank) getBalance() int {
return b.balance
}

func main() {
var wg sync.WaitGroup
var mux sync.RWMutex

wg.Add(10)

b := Bank{}

for i := 0; i < 5; i++ {
go func() {
mux.Lock()
b.saveMoney(1000) // 前後上鎖
mux.Unlock()
wg.Done()
}()
}
for i := 0; i < 5; i++ {
go func() {
mux.RLock()
_ = b.getBalance() // 讀的時候並發
mux.RUnlock()
wg.Done()
}()
}

wg.Wait()
fmt.Println(b.getBalance())
}

sync.Once

  • 情境:有一個 function,我們希望在 concurrency 時,只被所有 goroutine 做一次
package main

import (
"fmt"
"sync"
"time"
)

func main() {
var once sync.Once

for i := 0; i < 10; i++ {
go func() {
once.Do(read)
}()
}

time.Sleep(time.Second)
}

func read() {
fmt.Println(1)
}

Reference

Go 簡單例子來理解 sync.Mutex 和 sync.RWMutex