在用go实现raft之时,有众多的变量需要加锁,遇到了很多问题,以下为这些思考的总结
考虑极端的两种情况
为每个变量加锁
优点
- 省事:每个变量都有锁,各个变量的访问都很安全
缺点
- 性能差:访问和更改每个变量都需要加锁和解锁
- 依旧有场景不能满足:有时候我们需要同时保护多个变量不被修改和读取,直到某个行为完全完成。
整个大类使用一个变量
优点
- 省事:整个类的所有行为都串行执行,非常安全,也不会有死锁。
缺点
- 性能差:完全丧失多线程的性能提升,整个类的所有方法都不得不串行执行
- 可能产生死锁:比如一个类对外暴露了方法A和方法B,两个方法都是先加锁再执行,如果方法A调用了方法B,则产生死锁。
稍微总结一下可以看出,我们希望能尽可能避免死锁,尽可能减小锁的粒度来提升性能,同时也要保证有便捷的方式来同时锁住多个变量。想要实现这些目的,就不可能省事(o_o …
以下提出我所思考到的几种解决方案,相互不一定冲突,亦只作为抛砖引玉,渴望大佬们赏光与赐教。
切分对象
对于一个有十几个变量的对象,将相对独立的功能,或者几个内聚性比较强的变量,拆成一个独立的子对象。子对象对原本的对象提供方法,不提供变量。
优点
- 代码清晰:将一个大类拆分成小类,也能使代码更加简洁。
- 不容易产生死锁:如果拆分的好,确实不容易产生死锁。
缺点
- 拆分难:上面也说了,拆分好才能解决死锁问题。拆的不好,反而隐藏了死锁问题。
传参确定是否要上锁
这个直接举例子吧
type Obj struct {
mu sync.Mutex