golang互斥锁的那些事

369 阅读1分钟

死锁方案调研

  • go vet : 无法输出死锁日志,只能做静态检查
  • go -race: 无法输出死锁日志, 做一些并发安全的检查: 运行时检查
  • pprof: 需要在代码中开启一个web服务端程序,运行时检测
  • 引入第三方库:get github.com/sasha-s/go-deadlock: 把标准库的lock包装一层

推荐方案

  1. BuildTag="prod"替换成BuildTag="dev"
  2. 编译完跑自动化用例: 然后执行curl http://{ip}:8080/debug/pprof/goroutine?debug=1 -o pprof.log
  3. grep "runtime_SemacquireMutex" pprof.log, 有数据则有死锁可能性,否则没有死锁
  4. 有一定的误高率: 死锁的原理

死锁的模式

  • 正常模式(Barging): 吞吐量大,性能强。 获取锁资源时, 如果协程获取不到锁首先会自旋4次,然后挂在一个等待队列中。 当锁释放的时候,会唤醒队列中的第一个协程,此协程会和其他新获取锁的协程一起竞争, 但是获取锁成功概率较大的是新协程,这样造成的问题 是队头协程容易饿死。

  • 饥饿模式: 和正常模式不同的是:新获取锁的协程不会进入自旋状态, 而是排队。 这种模式比较公平, 但是性能不足

  • 模式切换: 如果一个协程等待锁资源的时间超过1ms, 就切到饥饿模式, 等待队列为空或者等待时间少于1ms就可以切换到正常模式

参考资料: