Go程序示例
package main
import (
"fmt"
"sync"
)
// 定义共享资源
var sharedData int
var mu sync.Mutex
var rwMutex sync.RWMutex
// 使用互斥锁进行写操作的函数
func writeWithMutex(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
sharedData++
mu.Unlock()
}
// 使用读写锁进行读操作的函数
func readWithRWMutex(wg *sync.WaitGroup) {
defer wg.Done()
rwMutex.RLock()
fmt.Printf("Read data: %d\n", sharedData)
rwMutex.RUnlock()
}
func main() {
var wg sync.WaitGroup
// 启动多个写操作
for i := 0; i < 3; i++ {
wg.Add(1)
go writeWithMutex(&wg)
}
// 启动多个读操作
for i := 0; i < 3; i++ {
wg.Add(1)
go readWithRWMutex(&wg)
}
wg.Wait()
}
同步机制优缺点分析
- 互斥锁(Mutex)
- 优点:
- 简单易用,适用于读写操作都需要独占访问共享资源的场景。无论是读操作还是写操作,都能保证同一时间只有一个goroutine可以访问共享资源,有效避免资源竞争。
- 可以保证数据的一致性,因为每次只有一个goroutine能修改共享资源。
- 缺点:
- 性能瓶颈明显,在读操作频繁的场景下,由于每次读操作都需要获取互斥锁,其他读操作也会被阻塞,导致并发性能降低。因为互斥锁不区分读和写,只要有一个goroutine获取了锁,其他所有goroutine无论是读还是写都得等待。
- 读写锁(RWMutex)
- 优点:
- 在读多写少的场景下性能优越。多个读操作可以同时进行,因为读操作不会修改共享资源,所以不会产生数据竞争。只有写操作需要独占锁,这样可以大大提高并发读的效率。
- 适用于大部分操作是读取共享资源,而写操作相对较少的应用场景,比如配置文件的读取和偶尔的更新。
- 缺点:
- 实现相对复杂,相比于互斥锁,需要更多的代码逻辑来管理读锁和写锁的获取与释放。
- 在写操作时,所有读操作和其他写操作都被阻塞,所以如果写操作频繁,可能会导致读操作长时间等待,降低系统整体的响应性。同时,如果写操作持有写锁时间过长,会影响读操作的并发性能。