作者回复: 这些go函数的真正执行谁先谁后是不可控的,所以这样做不行的。
作者回复: 我又看了一下“来碗绿豆汤”同学写的代码。我可能当时没看清楚,或者没说清楚。
他写的这段代码单从“顺序打印数字”的要求上看是可以的。但是这样做就变成纯同步的流程了,go函数就完全没必要写了。把go函数中的代码拿出来、删掉go函数,再把通道的相关代码也删掉,岂不是更直截了当?像这样:
for i := 0; i < num; i++ {
fmt.Println(i)
}
这个题目的要求是“使得在for循环中启用的多个goroutine按照既定的顺序运行”。你也可以把它理解为“在异步的情况下顺序的打印数字”。所以,“来碗绿豆汤”同学写的代码只满足了其中一个要求,而没有让go函数们自由的异步执行。
我的那个版本demo40.go是让各个go函数(确切地说,是它们调用的trigger函数)自行地检查所需条件,然后再在条件允许的情况下打印数字。这也叫“自旋”。这与纯同步的流程是有本质上的区别的。
作者回复: 可以加个sleep
作者回复: 很好,加油!
作者回复: Win下可能会有问题,你在bif语句后边加一句time.sleep(time.Nanosecond)。github上的代码我已经更新了。
作者回复: 搞这么多通道有些浪费啊。另外切片不是并发安全的数据类型,最好不要这样用。
作者回复: Go语言调度goroutine是准抢占式的,虽然会防止某个goroutine运行太久,并做换下处理。但是像简单的死循环这种有可能会换下失败,尤其是windows下,这跟操作系统的底层支持有关。不过一般情况下不用担心。
作者回复: 这主要是因为:Go 调度器在需要的时候只会对正在运行的 goroutine 发出通知,试图让它停下来。但是,它却不会也不能强行让一个 goroutine 停下来。
所以,如果一条 for 语句过于简单的话,比如这里的 for 语句就很简单(因为里面只有一条 if 语句),那么当前的 goroutine 就可能不会去正常响应(或者说没有机会响应)Go 调度器的停止通知。
因此,这里加一个 sleep 是为了:在任何情况下(如任何版本的 Go、任何计算平台下的 Go、任何的 CPU 核心数等),内含这条 for 语句的这些 goroutine 都能够正常地响应停止通知。
作者回复: 祝贺你升级了;)
作者回复: 你在win下执行的嘛?
作者回复: 可以加个sleep。
作者回复: 代码已经更新了。
作者回复: 对,可以。
作者回复: demo40.go我小改进了下,你再试试。我在服务器上也没出现你说的这个问题。Go语言很早的版本有可能这样,但是现在肯定不会了。你可联系下极客时间编辑,让她们把你加到群里。
作者回复: 并发情况下必须利用某种同步工具,否则就不是并发安全的,生产环境中很可能出现不可控的问题。
作者回复: 代码已经更新了,漏掉了。