理解真实世界的并发Bug

发表于:2019-3-19 13:59

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:oraoto    来源:思否

  Go带来了新的并发原语和并发模式(其实也不太新),如果没有深入了解这些特性,一样会写出并发bug
  在 Understanding Real-World Concurrency Bugs in Go 这篇论文里,作者系统地分析了6个流行的Go项目(Docker、Kubernetes、gRPC-go、etcd、CockroachDB、 BoltD)和其中171个并发bug,通过这些分析我们可以加深对Go的并发模型的理解,从而产出更好、更可靠的代码。
   Our study shows that it is as easy to make concurrency bugs with message passing as with shared memory,sometimes even more.
  我们的研究表明,消息传递和共享内存一样、有时甚至更容易写出并发错误。
  例如下面是k8s的一个bug,finishReq创建了一个子协程来执行fn然后通过select等待子协程完成或超时:
   func finishReq(timeout time.Duration) r ob {
  ch :=make(chanob)
  // ch :=make(chanob, 1) // 修复方案
  go func() {
  result := fn()
  ch <- result // 阻塞
  }
  select {
  case
  result = <- ch
  return result
  case <- time.After(timeout)
  return nil
  }
  }
  }
  如果超时先发生,或者子协程和超时同时发生但go运行时选择了超时分支(非确定性),子协程就会永远阻塞。
  Go并发模式使用情况
  这一节分析了6个项目里goroutine、并发原语的使用情况。
  
  匿名函数的goroutine使用比普通函数要多,基本每1~5千行代码创建一个goroutine。
  
  虽然Go鼓励消息传递,但是在这些大项目里,共享内存的使用比消息传递要多,Mutex基本在channel的两倍以上。
  Bug分类
  这篇论文里,按两个维度对bug进行分类:
  行为:阻塞和非阻塞,阻塞bug指goroutine意外地阻塞无法继续执行的情况(例如死锁),非阻塞bug通常是数据冲突
  原因:共享内存和消息传递,因为用了这两种技术之一导致的bug
  
  可以看到,共享内存其实导致了更多的bug。
  阻塞bug
 
  消息传递和共享内存导致的阻塞bug几乎一样多,而且消息传递的阻塞bug都和Go的消息传递语义例如channel有关,消息传递和共享内存一起使用的时候会很难发现bug。
  例如Docker错误使用WaitGroup导致阻塞:
   var group sync.WaitGroup
  group.Add(len(pm.plugins))
  for_, p := range pm.plugins {
  go func(p *plugin) {
  defer group.Done()
  }
  group.Wait() // 阻塞
  }
  // 应该在这里group.Wait()
  错误使用channel和mutex导致阻塞:
   func goroutine1() {
  m.Lock()
  ch <- request // 阻塞
  m.Unlock()
  }
  func goroutine2() {
  for{
  m.Lock()    // 阻塞
  m.Unlock()
  request <- ch
  }
  }
  非阻塞bug
  
  共享内存导致更多的非阻塞bug,几乎是消息传递的8倍。
  例如在下面这段代码里,每当ticker触发时执行一次f(),通过stopCh退出循环:
   ticker := time.NewTicker()
  for {
  f()
  select {
  case <- stopCh
  return
  case <- ticker
  }
  }
  但是select是非确定性的,stopCh和ticker同时发生时,不一定会执行stopChan的分支,正确做法是先检查一次stopCh:
   ticker := time.NewTicker()
  for {
  select{
  case <- stopCh:
  return
  default:
  }
  f()
  select {
  case <- stopCh:
  return
  case <- ticker:
  }
  }

      上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号