[0offer转Go的过程]
看到部分面经有手写交替打印的题目,这里以交替打印cat,dog,fish各100次为例子
包含一个错误解法和一个正确解法:
错误解法
package main
import "fmt"
func main() {
fmt.Println("正在打印")
ch1 := make(chan bool)
ch2 := make(chan bool)
ch3 := make(chan bool)
exit := make(chan bool)
go func() {
for i := 0; i < 100; i++ {
if ok := <-ch1; ok {
fmt.Printf("cat %d\n", i)
ch2 <- true
}
}
}()
go func() {
for i := 0; i < 100; i++ {
if ok := <-ch2; ok {
fmt.Printf("dog %d\n", i)
ch3 <- true
}
}
}()
go func() {
defer func() { exit <- true }()
for i := 0; i < 100; i++ {
if ok := <-ch3; ok {
fmt.Printf("fish %d\n", i)
}
}
}()
ch1 <- true
<-exit
}
这里报错的原因对初学者还是蛮难察觉到的(有兴趣可以自己分析)
正确解法
package main
import "fmt"
func main() {
fmt.Println("正在打印")
ch1 := make(chan bool)
ch2 := make(chan bool)
ch3 := make(chan bool)
exit := make(chan bool)
go func() {
for i := 0; i < 100; i++ {
if ok := <-ch1; ok {
fmt.Printf("cat %d\n", i)
ch2 <- true
}
}
}()
go func() {
for i := 0; i < 100; i++ {
if ok := <-ch2; ok {
fmt.Printf("dog %d\n", i)
ch3 <- true
}
}
}()
go func() {
defer func() { exit <- true }()
for i := 0; i < 100; i++ {
if ok := <-ch3; ok {
fmt.Printf("fish %d\n", i)
if i != 99 { // 如果i等于99了,就不要再向ch1通道写数据了,否则将导致ch1通道死锁
ch1 <- true
}
}
}
}()
ch1 <- true
<-exit
}
补充两点
- 对于第三个也就是最后打印fish的goroutine在遍历结束后,需要添加defer来告知程序切换到主goroutine
- 对于错误解法,出现的问题是在最后一次循环中,若仍然把true写入ch1,会造成没有接收,陷入阻塞