go 怎么等待所有的协程完成_理解真实世界中 Go 的并发 BUG

有几个学生研究归纳了go编程中的并发bugs,发表了一篇(英文)论文:《Understanding Real-World Concurrency Bugs in Go》。为你下载好了 PDF,关注公众号 Go语言中文网,回复 gostudy 获取。

在此做一个笔记,便于查阅。

文章以六个产品级go应用作为研究对象:Docker、Kubernetes、etcd、gRPC、CockroachDB、BoltDB,总共研究了这些应用中的171个bug,研究它们的根本原因,并重现这些bugs,以及检查它们的修复补丁。最后用两个现有go并发bug检测器测试了这些bug。

文章试图回答一个问题:对于两种线程/协程间通信机制,消息传递机制和共享内存机制,哪个更不容易出错?

文章从两个维度对bug进行了分类,bug原因(对共享内存的误用、对消息传递的误用)和bug表现(阻塞性bug、非阻塞性bug)。

研究结果及提交日志可以在以下地址查阅:https://github.com/system-pclub/go-concurrency-bugs

many concurrency bugs are caused by the mixed usage of message passing and other new semantics and new libraries in Go, which can easily be overlooked but hard to detect.

背景

使用共享内存实现同步

Go支持协程间共享内存,提供了多种传统的同步手段,如锁(Mutex)、读写锁(RWMutex)、条件变量(Cond)、原子读写(atomic)。go的RWMutex实现与C中的pthread_rwlock_t不同,go中的写锁请求优先级高于读锁。

go中还有一些新特性,Once保证一个函数只执行一次:使用 Once.Do(f) 方法,即使这一语句被多个协程调用了多次,也只有第一次的时候,函数f会被执行。

和C中的pthread_join类似,go使用WaitGroup来实现等待协程对其他协程的等待。

使用消息传递实现同步

channel(chan)是go的新特性,学习go语言编程的都应该熟悉了。channel分有缓冲和无缓冲两种(buffered and unbuffered)。

使用select可以从多路channel中进行选择。当有多路case有效时,select会从中随机选择一个去执行,这种随机性可能会造成bug。

Go引入了几种新机制来简化协程间的交互,如用context携带数据传递在不同协程之间,还有Pipe可在读协程和写协程之间传递流式数据。这两种都是新的消息传递机制,不注意的话可能引起新的并发bug。

Go并发模型

在研究并发bug前,文章先研究了go中的并发模型。

首先统计了那几个应用中创建gorutine的(静态)语句数量(位置数量),如下表:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值