并发
继续拓展上一节的代码,在最后部分,我们采用time.Sleep(time.Second * 5),等待5秒的方案来让main等待work1和work2完成,因为消耗少,所以work都在5秒内完成了工作,但实际工程中一个事务处理也许要超过5秒,靠给定等待时间的方案就不太适用了。
这里需要采用更精准的机制来应对此问题。引入go的默认包sync。
package main
import (
"fmt"
"sync"
)
func work1(n *sync.WaitGroup) {
defer n.Done()
for i := 0; i < 5; i++ {
fmt.Println("i am in work1")
}
}
func work2(n *sync.WaitGroup) {
defer n.Done()
for i := 0; i < 5; i++ {
fmt.Println("i am in work2")
}
}
func main() {
var mm sync.WaitGroup
mm.Add(2)
go work1(&mm)
go work2(&mm)
for i := 0; i < 5; i++ {
fmt.Println("i am in main")
}
//time.Sleep(time.Second * 5) 注释掉原来的等待时间方法
//采用新方案
mm.Wait()
}
sync提供WaitGroup类,有几个方法
1、通过Add方法,增加需要记住的协程(goroutinue)数量,相当于一个计数器。
2、各协程通过Done方法,减去当前计数器的值。每调用一次减一次。
3、主程通过Wait方法,等待计数器为0(即所有goroutinue结束),再执行下面的语句,没有就结束主程。
这也就是所谓的阻塞机制。
执行结果如下:
尾声
目前为止,所有的routine都是独立完成作业,不涉及相互之间信息交互。当涉及到各routine之间需要进行通信时,就要用到golang的管道(channel),channel自带阻塞机制。