撒的阿坎努斯 发表于 2018-9-20 07:02:38

Golang 探索对Goroutine的控制方法

前言
  在golang中,只需要在函数调用前加上关键字go即可创建一个并发任务单元,而这个新建的任务会被放入队列中,等待调度器安排。相比系统的MB级别线程栈,goroutine的自定义栈只有2KB,这使得我们能够轻易创建上万个并发任务,如此对性能提升不少。但随之而来的有以下几个问题:


[*]如何等待所有goroutine的退出
[*]如何限制创建goroutine的数量(信号量实现)
[*]怎么让goroutine主动退出
[*]探索——如何从外部杀死goroutine
  本文记录了笔者就以上几个问题进行探究的过程,文中给出了大部分问题的解决方案,同时也抛出了未解决的问题,期待与各位交流:p

准备
  开始之前先定义一个常量const N=100以及一个HeavyWork函数,假定该函数具有极其冗长、复杂度高、难以解耦的特性
  

func HeavyWork(id int) {  rand.Seed(int64(id))
  interval := time.Duration(rand.Intn(3)+1) * time.Second
  time.Sleep(interval)

  fmt.Printf("HeavyWork %-3d cost %v\n",>  
}
  

  以上定义的内容将在之后的代码中直接使用以缩减篇幅,大部分完整代码可在 Github: explore-goroutine 中找到

如何等待所有goroutine的退出
  "Do not communicate by sharing memory; instead, share memory by communicating"——GO的一大设计哲学《Share Memory By Communicating》
  
翻译成中文就是,用通信来共享内存数据,而不要通过共享内存数据来进行通信。
  
Go中的goroutines和channel提供了一种优雅而独特的结构化并发软件的方法,我们可以利用通道(channel)的特性,来实现当前等待goroutine的操作。但是channel并不是当前这个场景的最佳方案,用它来实现的方式是稍显笨拙的,需要知道确定个数的goroutine,同时稍不注意就极易产生死锁,代码如下:
  

// "talk is cheap, show me the code."  
func main() {
  waitChan := make(chan int, 1)
  for i := 0; i < N; i++ {
  go func(n int) {
  HeavyWork(n)
  waitChan
页: [1]
查看完整版本: Golang 探索对Goroutine的控制方法