资讯一个 golang 并发的问题

2021-05-11 20:28:24 +08:00
 ng29
func main() {
	runtime.GOMAXPROCS(1)
	ch := make(chan int)
	go count(ch, 10000)
	go count(ch, 10001)
	time.Sleep(10000 * time.Millisecond)
	fmt.Printf("exit\n")
}

func count(r chan int, who int) {
	for {
		if who%2 == 0 {
			r <- who
			fmt.Printf("|write <- who|%d\n", who)
		} else {
			<-r
			fmt.Printf("| <-r recv|%d\n", who)
		}
	}
}

输出是
| <-r recv|10001
| <-r recv|10001
|write <- who|10000
|write <- who|10000
为什么不是一个一个交替的形式
| <-r recv|10001
|write <- who|10000
| <-r recv|10001
|write <- who|10000
3439 次点击
所在节点    Go 编程语言
46 条回复
lesismal
2021-05-14 16:15:46 +08:00
@baiyi 其实就两点:
1. #20 里的 [3->4->1] 与 [2->5->6],这两段不包含 chan 的过程互相没影响的两个并发流,所以,跟 chan 没关系
2. 抢占式,随时可能被调度,跟是不是 print 也没关系

chan 和 print 都不是影响实际运行时的调度的充要条件,如果你多加一些 print,除了各自 goroutine 内的顺序能保证,多个 goroutine 之间的顺序没法保证
chan 、print 或者其他语句,是被调度器决定他们的执行权,他们反过来只能影响调度器对调度时间等的累计、调度时间的分配,但只是影响,影响是“可能会怎样”而不是“必然会怎样”
lesismal
2021-05-14 16:19:26 +08:00
@baiyi 你相当于是用可能性去解释必然性,所以会懵 :joy: :joy:
lesismal
2021-05-14 16:22:01 +08:00
@baiyi 放松一下,出门转转透透气,喝点茶水、咖啡,眺望下远方,过阵子再想,就豁然开朗了。有时候思考比较绕的问题会懵住,我也经常,有时候要一个问题纠结几天想不明白,然后放下了,突然某个时候又想起来、灵光一闪,灯火阑珊的感觉
baiyi
2021-05-14 17:06:11 +08:00
@lesismal #43 我明白你的意思,我现在已经不再认为我的示例代码中的顺序是一致的了,chan 也只是将接收器 /发送器标记为下一个要运行的 goroutine,但不能保证其一定是下一个运行的。哪怕是在我的示例代码中尽可能少的影响因素也是一样,因为还有抢占式调度。
我现在的结论也只是从 chan 的运行逻辑上解释两两输出的可能性,但 chan 不能必然导致两两输出。

其实结论已经不重要了,谢谢你帮我认识到我对于 go runtime 理解的不足。
lesismal
2021-05-14 20:04:27 +08:00
@baiyi 你的钻研精神非常棒,很赞,继续加油!
bigNewsMaker
2021-05-14 22:04:31 +08:00
楼上二位 V 站之光,赞

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

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

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

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

© 2021 V2EX