简述读写锁的使用,以及注意点
在读操作的时候 加读锁, 在写操作的时候加写锁,
举例:
多个协程需要读取、写入的操作
// 读操作
func reader(id int) {
for {
rwMutex.RLock()
fmt.Printf("Reader %d: Reading sharedData: %d\n", id, sharedData)
time.Sleep(time.Millisecond * time.Duration(rand.Intn(500)))
rwMutex.RUnlock()
}
}
// 写操作
func writer(id int) {
for {
newData := rand.Intn(100)
rwMutex.Lock()
fmt.Printf("Writer %d: Writing sharedData: %d\n", id, newData)
sharedData = newData
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
rwMutex.Unlock()
}
}
func main() {
// 启动多个读者和写者
for i := 0; i < 3; i++ {
go reader(i)
go writer(i)
}
...
}
1、是否选用
读写锁适用于读取操作远远多于写入操作的场景,在读取锁被多个协程持有, 可以提供并发性能。 但并不是所有场景都适合读写锁的, 写锁会阻塞其他读锁写锁的情况, 比如在写多读少的情况下就不适合读写锁, 会限制并发性能。
2、避免死锁的发生
使用读锁的时候, 不要套用写锁
3、注意锁的范围粒度
(看 sync.Mutex的使用注意点)
4、做好开发设设计、慎重考虑写锁情况
因为写锁会阻塞其他写锁、读锁的情况, 在选择使用读写锁后, 要考虑写锁的场景,确保写锁占用时间段
5、考虑其他同步机制
读写锁有时候并不能完全消除竞态条件, 不要局限锁。 要考虑其他同步机制。
其他同步机制有:waitGroup、 条件变量、原子操作、通道… …
源码解读