八. go 高性能编程之 读写锁和互斥锁的性能比较

一. 读写锁和互斥锁的区别

  1. 互斥锁(sync.Mutex): 互斥即不可同时运行
  2. 读写锁(sync.RWMutex):
  1. 读锁之间不互斥,没有写锁的情况下,读锁是无阻塞的,多个协程可以同时获得读锁。
  2. 写锁之间是互斥的,存在写锁,其他写锁阻塞。
  3. 写锁与读锁是互斥的,如果存在读锁,写锁阻塞,如果存在写锁,读锁阻塞。
  1. 对于sync.RWMutex提供了四个函数

Lock 加写锁
Unlock 释放写锁
RLock 加读锁
RUnlock 释放读锁

二. 读写锁和互斥锁性能比较

  1. 假定每个读写操作耗时 1 微秒,性能分析总结:
  1. 读写比为 9:1 时,读写锁的性能约为互斥锁的 8 倍
  2. 读写比为 1:9 时,读写锁性能相当
  3. 读写比为 5:5 时,读写锁的性能约为互斥锁的 2 倍
  1. 如果将单位读写操作的时间降为 0.1 微秒: 读写锁的性能优势下降到 3 倍,因加锁而阻塞的时间占比减小,互斥锁带来的损耗自然就减小了
  2. 单位读写操作时间增加到 10 微秒,读写锁和互斥锁的性能比与 1 微秒时基本一致

三. 互斥锁如何实现公平

  1. 互斥锁有两种状态:正常状态和饥饿状态。
  2. 在正常状态下,所有等待锁的 goroutine 按照FIFO顺序等待。唤醒的 goroutine 不会直接拥有锁,而是会和新请求锁的 goroutine 竞争锁的拥有。新请求锁的 goroutine 具有优势:它正在 CPU 上执行,而且可能有好几个,所以刚刚唤醒的 goroutine 有很大可能在锁竞争中失败。在这种情况下,这个被唤醒的 goroutine 会加入到等待队列的前面。 如果一个等待的 goroutine 超过 1ms 没有获取锁,那么它将会把锁转变为饥饿模式。
  3. 在饥饿模式下,锁的所有权将从 unlock 的 goroutine 直接交给交给等待队列中的第一个。新来的 goroutine 将不会尝试去获得锁,即使锁看起来是 unlock 状态, 也不会去尝试自旋操作,而是放在等待队列的尾部。
  4. 如果一个等待的 goroutine 获取了锁,并且满足一以下其中的任何一个条件:(1)它是队列中的最后一个;(2)它等待的时候小于1ms。它会将锁的状态转换为正常状态。
  5. 正常状态有很好的性能表现,饥饿模式也是非常重要的,因为它能阻止尾部延迟的现象
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值