第一次用 Golang 出面试题小记
最近一直在学习 Golang ,正好今天遇到一个七牛的候选人,就顺带出了一个多线程的题目让他用 Golang 写,在他写的过程中我担心自己没法给他 review code (我也是个新手),就在自己的电脑上尝试了一把,rush 的比较快,但是还是遇到了 docklock的问题,在这里记录一下
考题
用两个goroutine分别打印奇数和偶数的方式,输出1~10
实现思路
这个就是考核一下线程切换的,在java基本就是靠object.wait 和 object.notifyAll来实现,不够用Golang的channel 感受上会不太一样
这个题目的关键点有3个
- 确保奇数的goroutine是一定在偶数之前运行的
- 奇数和偶数的交替输出
- 程序正常退出
想法上就是弄4个channel
- startChan负责保证奇数一定先开始
- notifyEven和- notifyOdd用来做线程切换
- done用来做任务退出
| 1 | startChan := make(chan int) | 
buffer 的设计主要是done, 因为有2个goroutine, 防止在写入的时候block,给了2的buffer
Goroutine 代码
####奇数代码
| 1 | go func() { | 
####偶数代码
| 1 | go func() { | 
####主函数代码
| 1 | startChan <- 1 | 
解释一下
- 奇数线程pending 在<-startChan上,等主线程startChan <- 1来唤醒
- 奇数偶数之间互现唤醒和沉睡,做完全部工作后,调用done <- 1
- 主线程 block 在 <-done上,等所有工作线程做完了,主线程组再推出
一切看似很快就写完了,但是一运行,还是遇到了deadlock问题
问题排查和改进
deadlock bug fix
怎么会deadlock呢,想了一下,哦,原来奇数再打印了9以后就推出了,但是这个时候偶数还block在<-notifyEven上,所以就死锁了饿,Fix 非常简单,退出的时候通过notifyEven <- 1把偶数唤醒就好了
sync.WaitGroup
done 这个事情看起来就是以前 java 里面的join在做的事情,这种common的事情还要自己写,太low了,查了一下原来golang是有一个sync库做类似的事情,用waitGroup替换done就好了,最后贴一下现在的代码
| 1 | startChan := make(chan int) | 
此刻我想说一句,go写并发真有趣