题目:循环按序打印"dog"、“cat”、fish",分别使用三个 goroutine.
拿到题目,感觉简单又不简单的样子,先动手写一个最简单的打印:
func main() {
times := 100
go func() {
for i := 0; i<times; i++ {
println("dog")
println("cat")
println("fish")
}
}()
time.Sleep(100 * 1000) // 这时间我能算出来么,那用 channel 来接收吧
}
改进一下这让人无法预估的等待时间:使用 channel,在 goroutine 执行完之后通知主程序,巩固依稀 gorutine 和 channel 的基础知识:
- gorutine 是并发核心,main 函数也是一个 gorutine
- go func() {}() 匿名函数要注意参数传入
- channel 通过 make 创建,
make(chan typ)
需要声明好类型 - channel 通过
<-ch
ch <- data
来接收和发送信息 - channel
make(ch, int, 1
表示该 ch 是一个有1个数据缓冲的 chan,即在没有接收数据的情况下,第二条数据发送之后才会阻塞 func (ch chan <- int)
声明 ch 是一个单向 channelclose
后的 chan 依然可以接收缓冲通道的数据,但不可发送数据select {case <- ch: xx}
处理不同消息
func main() {
waitCh := make(chan struct{}, 1)
times := 100
go func() {
for i := 0; i < times; i++ {
println("dog")
println("cat")
println("fish")
}
waitCh <- struct{}{}
}()
<-waitCh
}
waitCh 听起来怎么这么熟悉呢?go 本身在面对这些情况已经实现了一个工具类,sync
包中提供的基础原语: waitGroup 。巩固一下:
- 官方描述:一个 WaitGroup 对象可以等待一组协程结束
- 我们可以通过
sync.WaitGroup
将原本顺序执行的代码在多个 Goroutine 中并发执行,加快程序处理的速度。 - 该类暴露三个接口:
add
wait
done
- 废话别说,show me the code 🙂
func main() {
wg := sync.WaitGroup{}
times := 100
wg.Add(1) // 协程数
go func() {
for i := 0; i < times; i++ {
println("dog")
println("cat")
println("fish")
}
wg.Done() // 协程执行完毕,一般复杂业务会有容错,确保执行: defer wg.Done()
}()
wg.Wait()
}
实现三个直接打印的 goroutine 必然不能保证有序,那就必须在 goroutine 间通信,cha -> chb -> chc->cha 循环触发则可以实现该功能。
func main() {
wg := sync.WaitGroup{}
wg.Add(3)
dogCh := make(chan struct{}, 1)
catCh := make(chan struct{}, 1)
fishCh := make(chan struct{}, 1)
times := 10
dogCounter, catCounter, fishCounter := 0, 0, 0
go PrintTheVal(dogCh, catCh, dogCounter, times, &wg, "dog") // &wg 需要取地址
go PrintTheVal(catCh, fishCh, catCounter, times, &wg, "cat")
go PrintTheVal(fishCh, dogCh, fishCounter, times, &wg, "fish")
dogCh <- struct{}{}
wg.Wait()
}
func PrintTheVal(selfCh, toCh chan struct{}, counter, max int, wg *sync.WaitGroup, val string) {
for {
<- selfCh
toCh <- struct{}{}
if counter >= max {
wg.Done()
return
}
println(val)
counter++
}
}
总结
- 通过简单的题目能快速理解基础语法,也能在实现简单题目中发现不足和巩固基础。
- 发散思维:其他同步原语的使用?