func main() {
boolChannel()
}
func boolChannel() {
ch1 := make(chan int)
ch2 := make(chan bool)
go func() {
for i:=0;i<5;i++ {
ch1 <- i
}
ch2 <- true //标识位写入 true
}()
go func() {
for x:= range ch1{
fmt.Println(x)
}
}()
<-ch2 //阻塞标识位
}
为什么这个输出结果一会是 0,1,2,3,一会是 0,1,2,3,4
按道理来说,我在主进程一直阻塞了,应该等 goroutine 全部打印完才对呀,百思不得其解
1
tottea 2020-05-17 11:16:17 +08:00
应该是 fmt.Println(x)这里的耗时吧,ch1 <- 4 完了之后马上 ch2 <- true,主协程一直阻塞后马上执行<-ch2,这时候 fmt.Println(4)这里卡在主协程结束前后,所以会有不稳定的情况
我的理解是这样 |
2
beidounanxizi 2020-05-17 11:16:55 +08:00
这不是很正常啊 打印的 goroutine 你有没有同步机制 去保证 先于 main goroutine 结束 ?
去看看 GMP 的调度把 |
3
smallyu 2020-05-17 11:19:11 +08:00
ch2 <- true 上面加一行 time.Sleep(1 * time.Second)
|
4
thet 2020-05-17 11:20:51 +08:00 via iPhone
<-ch2 接受到值,就往后执行了,这时候第二个 goroutine 可能还没执行完成
|
5
ysmood 2020-05-17 11:23:02 +08:00
删掉 ch2 <- true 就可以了
|
6
wangsongyan 2020-05-17 11:23:44 +08:00 via iPhone
打印完后再往 ch2 写值
|
7
cabing 2020-05-17 11:31:01 +08:00
加入 wait group 或者 context,不能保证你的 print 在 main 之前
|
8
CEBBCAT 2020-05-17 11:36:51 +08:00
这两个 go 出去的 func 并没有形成锁,只有第一个 func 和 boolChannel 形成了锁,所以你能确保的是全部写入后才会终结 boolChannel 的执行,但 fmt.Println(x)一定执行吗?不一定,因为可能正准备 fmt.Println(x),这个 goroutine 就被切到等待队列里了
(我不知道应不应该使用锁这个名词,基础忘掉了大半,欢迎拍砖) |
9
gamexg 2020-05-17 11:44:19 +08:00 via Android
第一个 go 协程结束时关闭信道
第二个协程直接在主线程执行。 ch2 可以去掉。 |
10
reus 2020-05-17 12:10:58 +08:00 1
ch2 <- true 改成 close(ch1)
ch2 <- true 移到第二个 for 后面 |
12
damingxing 2020-05-17 12:19:44 +08:00
4 进入 ch1 后,true 进入 ch2,
情况 1:主程序先得到 ch2,第二个 func 还没来得及得到 ch1 或者没来得及打印, 程序就退出 输出 0,1,2,3 情况 2:第二个 func 得到 ch1 并且打印,主程序还没来得及得到 ch2,输出 0,1,2,3,4 |
13
damingxing 2020-05-17 12:23:39 +08:00
ch2 <- true //标识位写入 true
这句放到第二个 func 后面就行了 |
14
ifconfig OP @damingxing 通俗易懂理解了,其实就是想看看不通过 waitGroup 能不能解决,多谢~
|
15
damingxing 2020-05-17 12:28:05 +08:00
@ifconfig 可以的,按照云风大侠的说法,通道是最佳解决方案
|
16
useben 2020-05-17 12:29:01 +08:00
一般是发送 goroutine 是 close 发送的 chan,接收 goroutine 是关闭阻塞 chan
这样的好处是不会造成 goroutine 泄露,发送完 close,接收 for chan 还是可以接收完数据的,会自己退出,这时候 close 或者发送信号到退出 chan 。 |