Go Channel 学习的一个疑问,请大佬指教

2020-05-17 11:08:50 +08:00
 ifconfig

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 全部打印完才对呀,百思不得其解

2699 次点击
所在节点    Go 编程语言
16 条回复
tottea
2020-05-17 11:16:17 +08:00
应该是 fmt.Println(x)这里的耗时吧,ch1 <- 4 完了之后马上 ch2 <- true,主协程一直阻塞后马上执行<-ch2,这时候 fmt.Println(4)这里卡在主协程结束前后,所以会有不稳定的情况
我的理解是这样
beidounanxizi
2020-05-17 11:16:55 +08:00
这不是很正常啊 打印的 goroutine 你有没有同步机制 去保证 先于 main goroutine 结束 ?

去看看 GMP 的调度把
smallyu
2020-05-17 11:19:11 +08:00
ch2 <- true 上面加一行 time.Sleep(1 * time.Second)
thet
2020-05-17 11:20:51 +08:00
<-ch2 接受到值,就往后执行了,这时候第二个 goroutine 可能还没执行完成
ysmood
2020-05-17 11:23:02 +08:00
删掉 ch2 <- true 就可以了
wangsongyan
2020-05-17 11:23:44 +08:00
打印完后再往 ch2 写值
cabing
2020-05-17 11:31:01 +08:00
加入 wait group 或者 context,不能保证你的 print 在 main 之前
CEBBCAT
2020-05-17 11:36:51 +08:00
这两个 go 出去的 func 并没有形成锁,只有第一个 func 和 boolChannel 形成了锁,所以你能确保的是全部写入后才会终结 boolChannel 的执行,但 fmt.Println(x)一定执行吗?不一定,因为可能正准备 fmt.Println(x),这个 goroutine 就被切到等待队列里了

(我不知道应不应该使用锁这个名词,基础忘掉了大半,欢迎拍砖)
gamexg
2020-05-17 11:44:19 +08:00
第一个 go 协程结束时关闭信道
第二个协程直接在主线程执行。

ch2 可以去掉。
reus
2020-05-17 12:10:58 +08:00
ch2 <- true 改成 close(ch1)

ch2 <- true 移到第二个 for 后面
ifconfig
2020-05-17 12:19:14 +08:00
@reus 大佬牛逼
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
damingxing
2020-05-17 12:23:39 +08:00
ch2 <- true //标识位写入 true
这句放到第二个 func 后面就行了
ifconfig
2020-05-17 12:25:16 +08:00
@damingxing 通俗易懂理解了,其实就是想看看不通过 waitGroup 能不能解决,多谢~
damingxing
2020-05-17 12:28:05 +08:00
@ifconfig 可以的,按照云风大侠的说法,通道是最佳解决方案
useben
2020-05-17 12:29:01 +08:00
一般是发送 goroutine 是 close 发送的 chan,接收 goroutine 是关闭阻塞 chan
这样的好处是不会造成 goroutine 泄露,发送完 close,接收 for chan 还是可以接收完数据的,会自己退出,这时候 close 或者发送信号到退出 chan 。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/672517

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX