首页 文章资讯内容详情

Golang 入门 : 等待 goroutine 完成任务

2026-06-01 4 花语

本文内容纲要:

-没有等待的情况 -使用Sleep函数等待 -使用channel -标准答案

Goroutine是Golang中非常有用的功能,但是在使用中我们经常碰到下面的场景:如果希望等待当前的goroutine执行完成,然后再接着往下执行,该怎么办?本文尝试介绍这类问题的解决方法。

没有等待的情况

让我们运行下面的代码,并关注输出的结果:

packagemain import( "time" "fmt" ) funcsay(sstring){ fori:=0;i<3;i++{ time.Sleep(100*time.Millisecond) fmt.Println(s) } } funcmain(){ gosay("helloworld") fmt.Println("over!") }

输出的结果为:

over!

因为goroutine以非阻塞的方式执行,它们会随着程序(主线程)的结束而消亡,所以程序输出字符串"over!"就退出了,这可不是我们想要的结果。

使用Sleep函数等待

要解决上面的问题,最简单、直接的方式就是通过Sleep函数死等goroutine执行完成:

funcmain(){ gosay("helloworld") time.Sleep(1000*time.Millisecond) fmt.Println("over!") }

运行修改后的程序,结果如下:

helloworld

helloworld

helloworld

over!

结果符合预期,但是太low了,我们不知道实际执行中应该等待多长时间,所以不能接受这个方案!

使用channel

通过channel也可以达到等待goroutine结束的目的,运行下面的代码:

funcmain(){ done:=make(chanbool) gofunc(){ fori:=0;i<3;i++{ time.Sleep(100*time.Millisecond) fmt.Println("helloworld") } done<-true }() <-done fmt.Println("over!") }

输出的结果也是:

helloworld

helloworld

helloworld

over!

这种方法的特点是执行多少次done<-true就得执行多少次<-done,所以也不是优雅的解决方式。

标准答案

Golang官方在sync包中提供了WaitGroup类型来解决这个问题。其文档描述如下:

AWaitGroupwaitsforacollectionofgoroutinestofinish.ThemaingoroutinecallsAddtosetthenumberofgoroutinestowaitfor.TheneachofthegoroutinesrunsandcallsDonewhenfinished.Atthesametime,Waitcanbeusedtoblockuntilallgoroutineshavefinished.

大意为:WaitGroup用来等待单个或多个goroutines执行结束。在主逻辑中使用WaitGroup的Add方法设置需要等待的goroutines的数量。在每个goroutine执行的函数中,需要调用WaitGroup的Done方法。最后在主逻辑中调用WaitGroup的Wait方法进行阻塞等待,直到所有goroutine执行完成。

使用方法可以总结为下面几点: 创建一个WaitGroup实例,比如名称为:wg 调用wg.Add(n),其中n是等待的goroutine的数量 在每个goroutine运行的函数中执行deferwg.Done() 调用wg.Wait()阻塞主逻辑

运行下面的代码:

packagemain import( "time" "fmt" "sync" ) funcmain(){ varwgsync.WaitGroup wg.Add(2) say2("hello",&wg) say2("world",&wg) fmt.Println("over!") } funcsay2(sstring,waitGroup*sync.WaitGroup){ deferwaitGroup.Done() fori:=0;i<3;i++{ fmt.Println(s) } }

输出的结果如下:

hello

hello

hello

world

world

world

over!

下面是一个稍稍真实一点的例子,检查请求网站的返回状态。如果要在收到所有的结果后进一步处理这些返回状态,就需要等待所有的请求结果返回:

packagemain import( "fmt" "sync" "net/http" ) funcmain(){ varurls=[]string{ "https://www.baidu.com/", "https://www.cnblogs.com/", } varwgsync.WaitGroup for_,url:=rangeurls{ wg.Add(1) gofetch(url,&wg) } wg.Wait() } funcfetch(urlstring,wg*sync.WaitGroup)(string,error){ deferwg.Done() resp,err:=http.Get(url) iferr!=nil{ fmt.Println(err) return"",err } fmt.Println(resp.Status) returnresp.Status,nil }

运行上面的代码,输出的结果如下:

200OK

200OK

参考:

HowtoWaitforAllGoroutinestoFinishExecutingBeforeContinuing

GoWaitGroupTutorial

本文内容总结:没有等待的情况,使用Sleep函数等待,使用channel,标准答案,

原文链接:https://www.cnblogs.com/sparkdev/p/10917536.html