Go语言学习之Go协程:WaitGroup

我们之前学习了协程和信道,里面有很多例子,当时为了保证main goroutine在所有的goroutine都执行完毕后在退出,我们使用了time.Sleep这种方式

由于写的demo都是很简单的,sleep个1秒,我们感觉应该是够用的

但是在实际开发中,我们无法预知,所有的goroutine需要多长时间才能执行完毕,sleep多了 主程序就会阻塞,sleep少了有的子协程的任务无法完成

我们今天来介绍一下 怎么优雅的处理这种情况

1.使用信道来标记完成

信道可以实现多个协程间的通信,那么我们只需要定义一个信道,在任务完成后,往信道中写入true,然后主协程中获取到true,就认为子协程执行完毕

import "fmt"

func main() {
    done := make(chan bool)
    //开一个协程去执行
    go func() {
        for i := 0; i < 5; i++ {
            fmt.Println(i)
        }
        //执行完毕,往信道里写入true
        done <- true
    }()
    //主协程中如果获取到信道里时true 就退出
    <-done
}    

输出如下

0
1
2
3
4

2.使用WaitGroup

上面使用的方法,在单个协程或者协程数量比较少的时候不会有什么问题,但在协程数多的时候,代码就会很复杂

更优雅的方式就是使用WaitGroup

WaitGroup只要实例化了就能用

var 实例名 sync.WaitGroup 

实例化完成后,就可以使用它的几个方法:

Add:初始值为0,你传入的值会往计数器上加,这里直接传入子协程的数量

Done: 当某个子协程完成后,可以调用此方法,就会从计数器上减1,通常可以使用defer来调用

Wait: 阻塞当前协程,知道计数器的值归0

举一个例子

// Startup the EventRouter
    //这里有一个协程, 所以计数器的值是1
    wg.Add(1)
//协程 go func() { //defer的作用是在eventRouter.run函数执行完,在执行defer的语句,所以这里就是程序执行完了,执行wg.Done()把计数器里的值减1 defer wg.Done() eventRouter.Run(stop) }() // Startup the Informer(s) glog.Infof("Starting shared Informer(s)") sharedInformers.Start(stop) //主协程一直调用wg.Wait()方法阻塞着,直到计数器的值为0在执行后面的代码 wg.Wait()
//执行这个代码的时候,说明计数器归0了,wg.Wait失效,不会阻塞主协程了 glog.Warningf("Exiting main()") os.Exit(1)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

上面使用信道的方法,在单个协程或者协程数少的时候,并不会有什么问题,但在协程数多的时候,代码就会显得非常复杂

上一篇:context


下一篇:Linux基础-磁盘列(如何创建raid10)