Go 语言中的锁类型与应用场景详解
· 阅读需 3 分钟
常用的锁的类型
锁类型 | 描述 | 用途 |
---|---|---|
Mutex | 互斥锁,一次只允许一个 goroutine 访问某个资源。 | 用于保护共享资源,避免并发写入时出现数据竞争。 |
RWMutex | 读写锁,允许多个读操作同时进行,但写操作是互斥的。 | 适用于读多写少的场景,可以提高在频繁读取时的性能。 |
Once | 一次性锁,确保某个操作在全局范围内只被执行一次。 | 主要用于资源的初始化,如单例模式的实现中保证只初始化一次。 |
Cond | 条件变量,用于等待或宣布事件的发生。 | 当 goroutine 需要等待某个条件满足时使用,常与 Mutex 或 RWMutex 配合使用。 |
RWMutex vs. Mutex
Mutex(互斥锁)
- 功能:提供基本的锁定功能,确保同一时刻只有一个 goroutine 可以访问资源。
- 适用场景:适用于对数据进行频繁写操作的场景。
RWMutex(读写锁)
- 优势:允许多个读取操作同时进行,而写操作则需独占资源。
- 性能优化:在读多写少的应用场景中,RWMutex 比 Mutex 更高效,因为它减少了读操作的等待时间。
代码示例
Mutex(互斥锁)
package main
import (
"fmt"
"sync"
)
var mutex sync.Mutex
var balance int
func Deposit(amount int) {
defer mutex.Unlock()
mutex.Lock()
balance += amount
}
func Balance() int {
defer mutex.Unlock()
mutex.Lock()
return balance
}
func main() {
Deposit(100)
fmt.Println("Current Balance:", Balance())
}
RWMutex(读写锁)
package main
import (
"fmt"
"sync"
)
var rwMutex sync.RWMutex
var data2 int
var wg sync.WaitGroup
func ReadData(id int) {
defer rwMutex.RUnlock()
rwMutex.RLock()
fmt.Printf("Goroutine %d read data: %d\n", id, data2)
wg.Done()
}
func WriteData(id, d int) {
defer rwMutex.Unlock()
rwMutex.Lock()
data2 = d
fmt.Printf("Goroutine %d write data: %d\n", id, d)
wg.Done()
}
func main() {
// 启动多个读写goroutines
numGoroutines := 10
wg.Add(numGoroutines * 2) // 因为有numGoroutines个读goroutine和numGoroutines个写goroutine
for i := 0; i < numGoroutines; i++ {
go WriteData(i, i*10) // 每个goroutine写入不同的数据
go ReadData(i) // 同时进行读操作
}
wg.Wait() // 等待所有goroutine完成
fmt.Println("Final Data:", data2)
}
Once(一次性锁)
package main
import (
"fmt"
"sync"
)
var once sync.Once
var value int
func Setup() {
value = 42
fmt.Println("Value set")
}
func DoSetup() {
once.Do(Setup)
}
func main() {
go DoSetup()
go DoSetup()
go DoSetup()
// WaitGroup 等待 goroutines 完成
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
DoSetup()
}()
go func() {
defer wg.Done()
DoSetup()
}()
go func() {
defer wg.Done()
DoSetup()
}()
wg.Wait()
fmt.Println("value:", value)
}
Cond(条件变量)
package main
import (
"sync"
"time"
)
var cond = sync.NewCond(&sync.Mutex{})
var ready bool
var wg4 sync.WaitGroup
// process 处理特定的进程,等待条件变量通知
func process(i int) {
defer wg4.Done()
defer cond.L.Unlock()
cond.L.Lock()
for !ready {
cond.Wait()
}
println("进程", i, "已准备就绪")
}
func main() {
for i := 0; i < 5; i++ {
wg4.Add(1)
go process(i)
}
println("所有协程已创建")
time.Sleep(2 * time.Second) // 确保所有子协程都进入等待状态
cond.L.Lock()
ready = true
cond.Broadcast()
cond.L.Unlock()
wg4.Wait() // 等待所有子协程完成
}