作者回复: 这是控制P的数量的。
作者回复: Go语言里只有传值,没有传引用。如果go函数是无参数的匿名函数,那么在它里面的fmt.Println函数的参数只会在go函数被执行的时候才会求值。到那个时候,i的值可能已经是10(最后一个数)了,因为for语句那时候可能已经都执行完毕了。
作者回复: 我再强调一下。在go语句执行后,Go运行时系统会把对应的go函数装进新启用的goroutine中,随后调度执行。因为这个调度是不保证先后顺序的,所以这些go函数的执行在默认情况下也是乱序的。因此,你这样写无法保证数字的顺序打印。
作者回复: 主要是因为计算机的内存(以及其他资源)总是有限的。从程序设计的角度讲,限制某种执行高并发任务的 goroutine 的数量也是很有必要的。另外,单进程内数十万的 goroutine 也会对 Go 语言的调度器和操作系统带来不小的压力。
再有,我们应该尽量地去量化程序对资源的使用,并且有节制地区使用资源。当然,具体的使用上限设定成多少合适,还有以实际压测的结果为准。
作者回复: 可运行 G 队列里面是先入先出的,可是调度器里有多个可运行 G 队列(每个 P 都有一个),而且哪个 G 什么进入哪个可运行G 队列还另有规则。所以这两句话并不矛盾。
作者回复: 不应该,我这里也正常,不知道你还改了什么。
作者回复: 这里的两个print是做对比用的吧。0~9顺序打印应该是第一个print打印出来的。你可以把两个print打印的东西分别加上不同的前缀。这样就容易区分了。
go函数的执行会稍微滞后一些,所以当 for 语句执行完的时候(迭代变量 i 会定格在 10 这个值上),有的go函数可能还没开始执行。等到它们执行的时候,打印变量 i,就只会打印出 10。
作者回复: sync.WaitGroup 用在这里不是很好。
作者回复: 可以从两个方面理解:
1. 这些 go 函数的执行顺序是不固定的。这个想必你已经理解了。
2. 当一个 fmt.Println 引发 I/O 操作的时候也可能被中断(被切换下 CPU)。当它再次获得运行机会的时候,也许其他的 fmt.Println 都打印完了。这种切换其实就是 Go 运行时系统进行调度的结果。