01简介Golang语言的一个优点就是天生就支持并发。在Golang语言开发中,我们通常使用的并发控制方式主要有Channel、WaitGroup和Context。在这篇文章中,我们主要介绍了Golang语言中的三种并发控制方式。每种方法如何使用?其中每一个的详细介绍在之前的文章中已经介绍过了,有兴趣的读者可以根据需要阅读。02Channel在Golang语言中,Channel不仅可以用于协程之间的通信,还可以用于控制子协程,使用Channel实现并发控制比较简单。比如下面的例子,我们在一个Golang应用中启动了两个协程,分别是主协程和子协程。主协程需要等待子协程运行完毕才能退出程序。示例代码:funcmain(){done:=make(chanstruct{})gofunc(){fmt.Println("goroutinerunover")done<-struct{}{}}()<-donefmt.Println("maingoroutinerunover")}看完上面的代码,子goroutine运行完毕后,我们通过Channel通知maingoroutine退出程序。事实上,这个过程是可以逆转的。主协程通知子协程退出程序,主协程向通道发送数据,子协程等待接收通道中的数据。03sync.WaitGroup如果在一个Golang应用中,主goroutine需要等待多个goroutine运行完毕才退出程序,应该如何实现呢?是的,也可以使用Channel来实现,但是有一种更优雅的实现方式,那就是WaitGroup,顾名思义,WaitGroup就是等待一组goroutines运行完毕。示例代码:funcmain(){wg:=sync.WaitGroup{}wg.Add(10)fori:=0;i<10;i++{gofunc(idint){fmt.Println(id,"操作结束")wg.Done()}(i)}wg.Wait()fmt.Println("maingoroutinerunover")}看上面的代码,我们启动了10个子goroutines,主goroutine需要等待10个子goroutine全部运行完才退出程序中,我们使用了WaitGroup,它有三个方法,分别是Add、Done和Wait。实际上,WaitGroup维护着一个计数器。这三种方法围绕这个计数器工作。Add用于设置计数器的值,Done用于减去计数器的值,Wait阻塞直到计数器的值为0。WaitGroup的源码解读在上一篇已经介绍过了。限于篇幅,这里不再赘述。04ContextChannel和WaitGroup通常用于父子goroutine应用的并发控制。如果在Golang应用中,子协程不断派生协程,我们应该如何控制呢?这种多层次的goroutine应用,我们可以使用Context来实现并发控制。示例代码:funcmain(){ctx,cancel:=context.WithCancel(context.Background())gofirstCtx(ctx)time.Sleep(5*time.Second)fmt.Println("stopallsubgoroutine")cancel()time.Sleep(5*time.Second)}funcfirstCtx(ctxcontext.Context){gosecondCtx(ctx)for{select{case<-ctx.Done():fmt.Println("firstdone")返回默认值:fmt.Println("firstrunning")time.Sleep(2*time.Second)}}}funcsecondCtx(ctxcontext.Context){for{select{case<-ctx.Done():fmt.Println("secondone")返回默认值:fmt.Println("secondrunning")time.Sleep(2*time.Second)}}}读取上面的代码,在子协程firstCtx中启动子协程secondCtx,主goroutine创建context,并将context传递给所有的子协程,然后主协程通过Callcancle停止所有子协程。05总结在这篇文章中,我们介绍了在不同的场景下,哪些方法适用于控制并发goroutine。其中,channel适合控制少量并发goroutine,WaitGroup适合控制一组并发goroutine,context适合控制多级并发goroutine。本文转载自微信公众号《Golang语言开发栈》,可通过以下二维码关注。转载本文请联系Golang语言开发栈公众号。
