人是一种高并发的物种,细品。golang
对 Go 语言的第一印象就是其原生地支持并发编程,并且使用的是协程,比线程更加轻量。编程
for i := 0; i < 10; i++ { go func(n int) { fmt.Println(n) }(i) }
最近有个项目须要同时调用多个 job,并要等待这些 job 完成以后才能往下执行。并发
最开始,咱们拥有一个执行 job 的方法,而且串行执行全部的 job:函数
func buildJob(name string) { ... } buildJob("A") buildJob("B") buildJob("C")
由于全部 job 是能够并发执行的,这样就不用必须等待上一个 job 执行完成后,才能继续执行其余 job。咱们可使用 Go 语言的关键字 go
来快速启用一个 goroutine
,下面咱们将并发地执行三个 job:高并发
go buildJob("A") go buildJob("B") go buildJob("C")
怎样才能知道每一个 job 是否已经完成,这里可使用 channel
进行通讯,并使用 select
检查执行结果:post
func buildJob(ch chan error, name string) { var err error ... // build job ch <- err // finnaly, send the result into channel } func build() error { jobCount := 3 errCh := make(err chan error, jobCount) defer close(errCh) // 关闭 channel go buildJob(errCh, "A") go buildJob(errCh, "B") go buildJob(errCh, "C") for { select { case err := <-ch: if err != nil { return err } } jobCount-- if jobCount <= 0 { break } } return nil }
当 job A 执行失败时,build
方法会 return err
退出,并执行 close(errCh)
。但是此时另外两个 job B 和 C 可能还没执行完成,同时也会把结果发给 errCh
,但因为这个时候 errCh
已经被关闭了,会致使程序退出 panic: send on closed channel
。优化
在给 channel 发送数据的时候,可使用接收数据的第二个值判断 channel 是否关闭:ui
func buildJob(ch chan error, name string) { var err error ... // build job if _, ok := <-ch; !ok { return } ch <- err // finnaly, send the result into channel } func build() error { jobCount := 3 errCh := make(err chan error, jobCount) defer close(errCh) // 关闭 channel go buildJob(errCh, "A") go buildJob(errCh, "B") go buildJob(errCh, "C") for { select { case err := <-ch: if err != nil { return err } } jobCount-- if jobCount <= 0 { break } } return nil }
Go 并发编程看似只须要一个关键字 go
就能够跑起来一个 goroutine
,但真正实践中,仍是有须要问题须要去处理的。spa
原文连接:https://k8scat.com/posts/code-with-golang-concurrency/线程