关于 goroutine 调度··GOMAXPROCS

2019-04-17 15:58:39 +08:00
 Fitz
package main

import (
	"runtime"
	"sync"
)

func main() {
	runtime.GOMAXPROCS(1)
	var wg sync.WaitGroup
	wg.Add(20)
	
	for i := 0; i < 10; i++ {
		go func(i int) {
			println(i)
			wg.Done()
		}(i)
	}
	
	for i := 10; i < 20; i++ {
		go func(i int) {
			println(i)
			wg.Done()
		}(i)
	}
	wg.Wait()
}

https://play.golang.org/p/nrEveScSaeI

问题: 执行结果为什么会先打印出 19 再顺序输出?请各位大佬不吝赐教

我记得之前有看过 M P G 模型中 GOMAXPROCS 可以控制 P 的数量

2820 次点击
所在节点    Go 编程语言
12 条回复
reus
2019-04-17 16:26:22 +08:00
偶然而已,按什么顺序都是对的,goroutine 的执行顺序是不确定的
Fitz
2019-04-17 16:28:47 +08:00
@reus 不是偶然 `GOMAXPROCS`设为 1 确实是顺序输出 只是最后一个先输出然后才开始顺序输出
keepeye
2019-04-17 16:30:14 +08:00
不专业的回答:最后一个 goroutine 会被放在一个"即将被执行的"地方,优先级最高。
话说,goroutine 不需要关心顺序吧
mscb
2019-04-17 16:31:45 +08:00
没仔细了解过细节。设置 gomaxprocs 后,应该只是控制 p 的数量,没有控制 m 的数量吧? m 不变的话底层还是会有多个线程,一个 g 阻塞了,其他 m 会来偷 g 过去运行。不知道我理解的对不对。欢以上仅供参考,欢迎各位大佬赐教,确实没仔细了解过调度这一块
punyGod
2019-04-17 16:33:18 +08:00
它会把最新的一个放到本地的 queue 中。这样它就会被优先执行
mscb
2019-04-17 16:35:56 +08:00
另外就算是单线程的协程也不能保证能顺序执行哇。主要看添加到队列里的形态,以及调度的情况
Fitz
2019-04-17 16:36:11 +08:00
@mscb 可是 m 执行需要 p 提供 context 吧
Fitz
2019-04-17 16:36:57 +08:00
@punyGod 应该都在 local queue 里吧
reus
2019-04-17 16:39:41 +08:00
@Fitz 你可以试下用 go run -race 跑,多跑几次,看看是不是偶然。
reus
2019-04-17 16:42:37 +08:00
@Fitz 讨论这种未定义行为没有任何意义,开了竞态检测,顺序就可能不同。不同版本的调度器也有可能不同,不同的编译器实现的运行时也可能不同。所以这就是偶然的行为,你的程序是不可以依赖这种未定义行为的。
mscb
2019-04-17 16:43:18 +08:00
@Fitz 对,你说的没错。P 是为 m 提供一个上下文队列。不过除了一个 P 以外还有一个全局的 P,当 local P 满了以后,g 会移动到 global P 里面,由于 go 添加的队列时间不同说不定会导致 local 和 global 内的 g 顺序不一致呢。
Fitz
2019-04-17 16:54:38 +08:00
@reus @mscb 确实 开了竞态检测 输出就会不同。感谢解答!!

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

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

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

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

© 2021 V2EX