版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1.前言 在上一篇文章读写锁为什么那么快?(1)中,萌叔探讨了读写锁提高程序性能的原因。这一篇文章,萌叔将聊聊读写锁面临的2个问题。并看看标准库的是如何实现。 2.几个问题 Q1: 如何避免写锁饥饿或者读锁饥饿问题? 我们知道读写锁的特性:同一时刻允许多个线程(协程)对共享资源进行读操作, 也就是说多个线程(协程)可以多次加读锁。那么会出现这样一种情况,读锁还没有被完全释放的情况(读锁计数器大于0),又有新的读操作请求加读锁。这样写协程永远无法加上写锁,将会一直阻塞。 A1: 标准库实际上引入某种类似排队的机制 如上图所示,协程G1、G2、G3、G4并发访问共享资源。它们请求加锁的顺序为矩形的左边沿,耗时为矩形块的长度 t1时刻,G1加上了读锁,开始读操作 t2时刻,G2也加上了读锁,进行读操作 t3时刻,G3表示它要进行写操作 t4时刻,G4也想加读锁,并且现在共享资源上施加的读锁还没有完全释放(需要到t5时刻才能释放),但是由于G3已经表示它需要加写锁了,所以G4将会阻塞 所以实际的运行顺序是 Q2: 如何确保加读锁时,成本尽可能的低? 读写锁最适用的情况是读多写少的场景,降低读锁的加锁和释放锁的开销,才能提高整体的吞吐能力。 A2: 读协程和写协程互斥仅用的到int32的整数 萌叔虽然也使用condition实现了读写锁,但由于 condition要求在判断条件是否满足,以及修改条件中相关联的变量时,都需要加互斥锁,因此萌叔的实现性能和标准库有一定的差距。 写协程和写协程的互斥靠的是标准库的互斥锁 3.代码 标准库的实现很巧妙,阅读有一定的难度。萌叔将对部分代码进行注释,并讲解。 package sync import ( “internal/race” “sync/atomic” “unsafe” ) type RWMutex struct { w Mutex // held… 继续阅读 读写锁为什么那么快?(2)

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1.实验 首先让我们来看一组单元测试结果,看看互斥锁和读写锁在不同场景下的表现。 这里使用了极客兔兔的《Go 语言高性能编程》中的case,在此特别鸣谢 vearne/golab BenchmarkReadMore-4 1 1195229024 ns/op BenchmarkReadMoreRW-4 9 122810085 ns/op BenchmarkReadMoreMyRW-4 8 145523134 ns/op BenchmarkWriteMore-4 1 1296582090 ns/op BenchmarkWriteMoreRW-4 1 1194438009 ns/op BenchmarkWriteMoreMyRW-4 1 1247918412 ns/op BenchmarkEqual-4 1 1344248968 ns/op BenchmarkEqualRW-4 2 661674534 ns/op BenchmarkEqualMyRW-4 2 685353924 ns/op… 继续阅读 读写锁为什么那么快?(1)