看到这样一个golang的面试题,大致是:
有三个函数分别打印,“dog”,“cat”,“fish”,
要求每个函数起一个goroutine,请按照dog,cat,fish的顺序,打印四次,输出到控制台。
思考:其实这道题,就是在考察两点:
1.goroutine和channel的配合,使用来控制多个协程的执行顺序;
2.如何控制协程执行的次数;(sync包)
package main
import (
"fmt"
"sync"
)
func main(){
wg:=sync.WaitGroup{}
wg.Add(12) //打印四组,三个goroutine需要执行4次,3*4表示处于等待goroutine的数量
dogChan:=make(chan bool,1) //此处如果申明的是无缓冲的通道,那么会在16行代码处处于阻塞状态!原因:通道中无数据,向通道写数据,但无协程读取。
catChan:=make(chan bool)
fishChan:=make(chan bool)
dogChan<-true
for i:=0;i<4;i++{ //打印四组,三个goroutine需要执行4次
go dog(&wg,dogChan,catChan)
go cat(&wg,catChan,fishChan)
go fish(&wg,fishChan,dogChan)
}
wg.Wait()
fmt.Println("main finished!")
}
func dog(wg *sync.WaitGroup,dogChan chan bool,catChan chan bool){
if ok:=<-dogChan;ok {
fmt.Println("dog")
wg.Done()
catChan<-true
}
}
func cat(wg *sync.WaitGroup,catChan chan bool,fishChan chan bool){
if ok:=<-catChan;ok {
fmt.Println("cat")
wg.Done()
fishChan<-true
}
}
func fish(wg *sync.WaitGroup,fishChan chan bool,dogChan chan bool){
if ok:=<-fishChan;ok {
fmt.Println("fish")
wg.Done()
dogChan<-true
}
}
输出:
dog
cat
fish
dog
cat
fish
dog
cat
fish
dog
cat
fish
main finished!
Process finished with exit code 0
仔细看,发现上面不符合题意,实际上起了12个协程!控制每个协程的执行顺序,实现了4组dog,cat,fish的输出。
如果要限制协程为3个,怎么搞?
package main
import (
"fmt"
"sync"
)
func PrintCat(dogChan,catChan chan bool){
defer wg.Done()
defer close(catChan)
for i:= 0; i <4;i++{
<-dogChan
fmt.Println("cat ...")
catChan <- true
}
}
func PrintDog(fishChan,dogChan chan bool){
defer wg.Done()
defer close(dogChan)
for i:= 0; i <4;i++{
<-fishChan
fmt.Println("dog ...")
dogChan<-true
}
}
func PrintFish(catChan,fishChan chan bool){
defer wg.Done()
defer close(fishChan)
for i:= 0; i <4;i++{
<-catChan
fmt.Println("fish ...")
fishChan<-true
}
}
var wg sync.WaitGroup
func main() {
dogChan := make(chan bool,1)
catChan := make(chan bool,1)
fishChan := make(chan bool,1)
fishChan <- true
go PrintDog(fishChan,dogChan)
go PrintFish(catChan,fishChan)
go PrintCat(dogChan,catChan)
wg.Add(3)
wg.Wait()
}
参考文档: