go面试-交替打印数字和字母

1,673 阅读1分钟

面试题本身不是我原创,摘自大佬 觉得有用可以给大佬点个start吧

image.png

交替打印数字和字母

问题描述

使用两个 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()

项目执行流程

  1. 定义两个bool类型的channel赋值给letter和number
  2. 定义一个等待组,阻塞协程等整个协程执行结束后才退出
  3. 启动第一个协程(后续称A协程),死循环,但是由于select多路复用,number为false值阻塞,发生协程切换
  4. 等待组原子+1
  5. 启动第二个协程(后续称协程B)并传入协程命名空间,死循环去select letter但是由于letter false阻塞
  6. number channel 推入true值, 协程A中的number值获取到为true,代码执行
  7. 根据协程A中的循环 i初始值为1 打印1,i自增1,再次打印i,打印2,自增1,letter放入bool true
  8. 协程B触发,协程B中的i初始值为A,判断'A' >= 'Z' false, 所以不走里面的done和return逻辑,输出字符串'A',i自增1,输出字符串'B',自增1,number放入true,触发协程A
  9. 直到i >= 'Z' ,触发 等待组-1并退出循环, 等待组的wait。检测到 waitgroup中的原子锁为0,程序执行完毕可以退出
  10. 整个程序生命周期结束