今天读了篇分析Go语言并发Bugs的论文Understanding Real-World Concurrency Bugs in Go (中文版的可以直接看作者的博士论文 )
大致探讨的问题是:Go号称让并发编程更简单、写出来的并发程序更健壮,那么Go的CSP式写法真的比共享内存式的并发编程less error-prone吗?
为了探究这个问题,作者找了6个开源的Go语言写的开源项目,统计了历史上的171个bug,发现CSP写法一样很容易出Bug。统计数据可以直接看论文里的图表,有意思的是作者把Bug分类为阻塞类和非阻塞类,阻塞类Bug里,Message Passing引起的Bug比传统共享内存式写法引起的Bug更多(如图);非阻塞类Bug里,共享内存式写法引起的问题较多。
image.png
作者于是得出结论:message passing写法并不比共享内存写法less error-prone
image.png
感想:
- 有人指出这个归因逻辑有问题,要得出这样的结论得有同一个程序一份用CSP写、另一份用共享内存写,然后比较两者数据。Kubernetes那么大,全换成共享内存式写法说不定Bug更多呢
- 即使这个归因有问题,至少可以得出结论:CSP式写法可能不比共享内存式写法less error-prone。这样的结论也是有意义的。
- 想到个问题:相比于非阻塞式Bug,我们是否更应该关注阻塞式Bug?直觉上想,非阻塞式Bug顶多是数据竞争时出个业务逻辑Bug影响某个业务,但是阻塞式Bug不管是死锁还是阻塞导致goroutine泄漏,都更可能造成系统性的崩溃。没细想。
//TODO - 这种实证研究没必要执着于归因吧(上哪找同一个程序一份用A写一份用B写拿来做研究?实践中找不着这样的案例),更值得探讨的是Amdahl定律:怎么解决瓶颈?比如既然58%的阻塞式Bug是CSP写法写出来的、既然CSP写法容易出阻塞式Bug,那么怎么避免CSP写出阻塞Bug、怎么及时发现写出来的阻塞Bug?作者博士论文里讲他们搞了个静态检测,我不懂静态检测就没看:)
5.作为Go programmer,可以看看论文里的Bug案例、Bug分类避免实践中踩坑,就当看Effective Java了
网友评论