题目描述
请你用你熟悉的语言,实现:给一个数字n,用2个线程分别输出1,3,5,7,9,…和2,4,6,8,10,…,一直到n,但最终输出的结果是1,2,3,4,5,6,7,8,9,10,…,n
示例
n=100
结果:1,2,3,…,99,100
代码
func PrintN(n int) {
// 定义2个chan,分别控制2个go runtine运行
r1, r2 := make(chan bool, 1), make(chan bool, 1)
// 定义结束chan
stop := make(chan bool, 2)
// 启动第一个go runtine
go func() {
r1 <- true
}()
// go runtine1
go func(i int) {
for {
select {
case <-r1:
fmt.Printf("%d,", i)
i += 2
r2 <- true
if i >= n {
stop <- true
return
}
}
}
}(1)
// go runtine2
go func(i int) {
for {
select {
case <-r2:
fmt.Printf("%d,", i)
i += 2
r1 <- true
if i > n {
stop <- true
return
}
}
}
}(2)
// 监听结束信号
<-stop
<-stop
// 关闭chan
close(r1)
close(r2)
close(stop)
}
结果:
当n=100
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,
分析
题目看起来很简单,当你真正上手写代码的时候很容易遇到各种问题。建议自己动手试一试。
当然面试官的题目不会这么简单,这个时候会对你的代码提出一些要求,比如,只用一个chan怎么实现呢?(如果你一开始就想到一个chan实现那很棒哦)
用一个chan实现
func PrintN(n int) {
// 定义chan
run := make(chan bool)
// 定义结束chan
stop := make(chan bool, 2)
// go runtine1
go func(i int) {
for {
fmt.Printf("%d,", i)
i += 2
run <- true
if i >= n {
stop <- true
return
}
}
}(1)
// go runtine2
go func(i int) {
for {
<-run
fmt.Printf("%d,", i)
i += 2
if i > n {
stop <- true
return
}
}
}(2)
// 监听结束信号
<-stop
<-stop
// 关闭chan
close(run)
close(stop)
}
当n=100,结果如下
1,3,2,4,5,7,6,8,9,11,10,12,13,15,14,16,17,19,18,20,21,23,22,24,25,27,26,28,29,31,30,32,33,35,34,36,37,39,38,40,41,43,42,44,45,47,46,48,49,51,50,52,53,55,54,56,57,59,58,60,61,63,62,64,65,67,66,68,69,71,70,72,73,75,74,76,77,79,78,80,81,83,82,84,85,87,86,88,89,91,90,92,93,95,94,96,97,99,98,100
看起来是对的,当你仔细一想,发现1,3,2,4,5,7,6,…什么鬼,竟然是错的。仔细阅读代码发现,当go2<-run
代码接收到go1发的信号并开始执行fmt.Printf("%d,", i)
的时候,此时go1run <- true
代码也停止阻塞并且继续执行,因此go1也可以执行fmt.Printf("%d,", i)
了,这个时候go1可能在go2前面执行fmt.Printf("%d,", i)
,因此就出现了1,3,2这种情况,改如何解决呢?
我们将代码稍微做一点改动
func PrintN(n int) {
// 定义chan
run := make(chan bool)
// 定义结束chan
stop := make(chan bool, 2)
// go runtine1
go func(i int) {
for {
fmt.Printf("%d,", i)
i += 2
run <- true
run <- true
if i >= n {
stop <- true
return
}
}
}(1)
// go runtine2
go func(i int) {
for {
<-run
fmt.Printf("%d,", i)
i += 2
<-run
if i > n {
stop <- true
return
}
}
}(2)
// 监听结束信号
<-stop
<-stop
// 关闭chan
close(run)
close(stop)
}
改动点:
- go2 在执行
fmt.Printf("%d,", i)
后再监听一次run - go1 连续2次向run中写入数据
逻辑分析:go2监听2次run,第一次监听完了表示go1还不能执行,要等go2执行完fmt.Printf("%d,", i)
后,go1再写一次run,go2监听到第二次run后,表示go2执行完成了,go1可以执行了。
总结
每日学习一点,日积月累