面试题本身不是我原创,摘自大佬 觉得有用可以给大佬点个start吧
交替打印数字和字母
问题描述
使用两个 goroutine 交替打印序列,一个 goroutine 打印数字, 另外一个 goroutine 打印字母, 最终效果如下:
12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728
解题思路
问题很简单,使用 channel 来控制打印的进度。使用两个 channel ,来分别控制数字和字母的打印序列, 数字打印完成后通过 channel 通知字母打印, 字母打印完成后通知数字打印,然后周而复始的工作。
letter,number := make(chan bool),make(chan bool)
wait := sync.WaitGroup{}
go func() {
i := 1
for {
select {
case <-number:
fmt.Print(i)
i++
fmt.Print(i)
i++
letter <- true
}
}
}()
wait.Add(1)
go func(wait *sync.WaitGroup) {
i := 'A'
for{
select {
case <-letter:
if i >= 'Z' {
wait.Done()
return
}
fmt.Print(string(i))
i++
fmt.Print(string(i))
i++
number <- true
}
}
}(&wait)
number<-true
wait.Wait()
项目执行流程
- 定义两个bool类型的channel赋值给letter和number
- 定义一个等待组,阻塞协程等整个协程执行结束后才退出
- 启动第一个协程(后续称A协程),死循环,但是由于select多路复用,number为false值阻塞,发生协程切换
- 等待组原子+1
- 启动第二个协程(后续称协程B)并传入协程命名空间,死循环去select letter但是由于letter false阻塞
- number channel 推入true值, 协程A中的number值获取到为true,代码执行
- 根据协程A中的循环 i初始值为1 打印1,i自增1,再次打印i,打印2,自增1,letter放入bool true
- 协程B触发,协程B中的i初始值为A,判断'A' >= 'Z' false, 所以不走里面的done和return逻辑,输出字符串'A',i自增1,输出字符串'B',自增1,number放入true,触发协程A
- 直到i >= 'Z' ,触发 等待组-1并退出循环, 等待组的wait。检测到 waitgroup中的原子锁为0,程序执行完毕可以退出
- 整个程序生命周期结束