Go语言中怎么对Concurrency进行管理

这篇文章给大家介绍 Go语言中怎么对Concurrency进行管理 ,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

创新互联2013年开创至今,是专业互联网技术服务公司,拥有项目成都网站设计、成都网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元大宁做网站,已为上家服务,为大宁各地企业和个人服务,联系电话:13518219792

WaitGroup

先来了解有什么情境需要使用到  WaitGroup,假设您有两台机器需要同时上传最新的代码,两台机器分别上传完成后,才能执行最后的重启步骤。就像是把一个工作同时拆成好几份同时一起做,可以减少时间,但是最后需要等到全部做完,才能执行下一步,这时候就需要用到  WaitGroup 才能做到。

package main  import (     "fmt"     "sync" )  func main() {     var wg sync.WaitGroup     i := 0     wg.Add(3) //task count wait to do     go func() {         defer wg.Done() // finish task1         fmt.Println("goroutine 1 done")         i++     }()     go func() {         defer wg.Done() // finish task2         fmt.Println("goroutine 2 done")         i++     }()     go func() {         defer wg.Done() // finish task3         fmt.Println("goroutine 3 done")         i++     }()     wg.Wait() // wait for tasks to be done     fmt.Println("all goroutine done")     fmt.Println(i) }

Channel

另外一种实际的案例就是,我们需要主动通知一个 Goroutine 进行停止的动作。换句话说,当 App 启动时,会在后台跑一些监控程序,而当整个 App  需要停止前,需要发个 Notification 给后台的监控程序,将其先停止,这时候就需要用到 Channel 来通知。看下下面这个例子:

package main  import (     "fmt"     "time" )  func main() {     exit := make(chan bool)     go func() {         for {             select {             case <-exit:                 fmt.Println("Exit")                 return             case <-time.After(2 * time.Second):                 fmt.Println("Monitoring")             }         }     }()     time.Sleep(5 * time.Second)     fmt.Println("Notify Exit")     exit <- true //keep main goroutine alive     time.Sleep(5 * time.Second) }

上面的例子可以发现,用了一个 Gogourtine 和 Channel 来控制。可以想像当后台有无数个 Goroutine 的时候,我们就需要用多个  Channel 才能进行控制,也许 Goroutine 内又会产生 Goroutine,开发者这时候就会发现已经无法单纯使用 Channel 来控制多个  Goroutine 了。这时候解决方式会是传递 Context。

Context

大家可以想像,今天有一个后台任务 A,A 任务又产生了 B 任务,B 任务又产生了 C 任务,也就是可以按照此模式一直产生下去,假设中途我们需要停止 A  任务,而 A 又必须告诉 B 及 C 要一起停止,这时候通过 context 方式是最快的了。

package main  import (     "context"     "fmt"     "time" )  func foo(ctx context.Context, name string) {     go bar(ctx, name) // A calls B     for {         select {         case <-ctx.Done():             fmt.Println(name, "A Exit")             return         case <-time.After(1 * time.Second):             fmt.Println(name, "A do something")         }     } }  func bar(ctx context.Context, name string) {     for {         select {         case <-ctx.Done():             fmt.Println(name, "B Exit")             return         case <-time.After(2 * time.Second):             fmt.Println(name, "B do something")         }     } }  func main() {     ctx, cancel := context.WithCancel(context.Background())     go foo(ctx, "FooBar")     fmt.Println("client release connection, need to notify A, B exit")     time.Sleep(5 * time.Second)     cancel() //mock client exit, and pass the signal, ctx.Done() gets the signal  time.Sleep(3 * time.Second)     time.Sleep(3 * time.Second) }  package main  import (     "context"     "fmt"     "time" )  func foo(ctx context.Context, name string) {     go bar(ctx, name) // A calls B     for {         select {         case <-ctx.Done():             fmt.Println(name, "A Exit")             return         case <-time.After(1 * time.Second):             fmt.Println(name, "A do something")         }     } }  func bar(ctx context.Context, name string) {     for {         select {         case <-ctx.Done():             fmt.Println(name, "B Exit")             return         case <-time.After(2 * time.Second):             fmt.Println(name, "B do something")         }     } }  func main() {     ctx, cancel := context.WithCancel(context.Background())     go foo(ctx, "FooBar")     fmt.Println("client release connection, need to notify A, B exit")     time.Sleep(5 * time.Second)     cancel() //mock client exit, and pass the signal, ctx.Done() gets the signal  time.Sleep(3 * time.Second)     time.Sleep(3 * time.Second) }

大家可以把 context 想成是一个 controller,可以随时控制不确定个数的  Goroutine,由上往下,只要宣告context.WithCancel后,再任意时间点都可以通过cancel()来停止整个后台服务。实际案例会用在当 App  需要重新启动时,要先通知全部 goroutine 停止,正常停止后,才会重新启动 App。

总结

根据不同的情境跟状况来选择不同的方式,做一个总结:

  • WaitGroup:需要将单一个工作分解成多个子任务,等到全部完成后,才能进行下一步,这时候用 WaitGroup 最适合了

  • Channel + Select:Channel 只能用在比较单纯的 Goroutine 情况下,如果要管理多个 Goroutine,建议还是 走  context 会比较适合

  • Context:如果您想一次控制全部的 Goroutine,相信用 context 会是最适合不过的。

关于 Go语言中怎么对Concurrency进行管理 就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


文章名称:Go语言中怎么对Concurrency进行管理
转载注明:http://ybzwz.com/article/ppcgoe.html