V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Fitz
V2EX  ›  Go 编程语言

关于 goroutine 调度··GOMAXPROCS

  •  
  •   Fitz · 2019-04-17 15:58:39 +08:00 · 2798 次点击
    这是一个创建于 2051 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 的数量

    12 条回复    2019-04-17 16:54:38 +08:00
    reus
        1
    reus  
       2019-04-17 16:26:22 +08:00
    偶然而已,按什么顺序都是对的,goroutine 的执行顺序是不确定的
    Fitz
        2
    Fitz  
    OP
       2019-04-17 16:28:47 +08:00
    @reus 不是偶然 `GOMAXPROCS`设为 1 确实是顺序输出 只是最后一个先输出然后才开始顺序输出
    keepeye
        3
    keepeye  
       2019-04-17 16:30:14 +08:00
    不专业的回答:最后一个 goroutine 会被放在一个"即将被执行的"地方,优先级最高。
    话说,goroutine 不需要关心顺序吧
    mscb
        4
    mscb  
       2019-04-17 16:31:45 +08:00 via Android
    没仔细了解过细节。设置 gomaxprocs 后,应该只是控制 p 的数量,没有控制 m 的数量吧? m 不变的话底层还是会有多个线程,一个 g 阻塞了,其他 m 会来偷 g 过去运行。不知道我理解的对不对。欢以上仅供参考,欢迎各位大佬赐教,确实没仔细了解过调度这一块
    punyGod
        5
    punyGod  
       2019-04-17 16:33:18 +08:00
    它会把最新的一个放到本地的 queue 中。这样它就会被优先执行
    mscb
        6
    mscb  
       2019-04-17 16:35:56 +08:00 via Android
    另外就算是单线程的协程也不能保证能顺序执行哇。主要看添加到队列里的形态,以及调度的情况
    Fitz
        7
    Fitz  
    OP
       2019-04-17 16:36:11 +08:00
    @mscb 可是 m 执行需要 p 提供 context 吧
    Fitz
        8
    Fitz  
    OP
       2019-04-17 16:36:57 +08:00
    @punyGod 应该都在 local queue 里吧
    reus
        9
    reus  
       2019-04-17 16:39:41 +08:00
    @Fitz 你可以试下用 go run -race 跑,多跑几次,看看是不是偶然。
    reus
        10
    reus  
       2019-04-17 16:42:37 +08:00   ❤️ 1
    @Fitz 讨论这种未定义行为没有任何意义,开了竞态检测,顺序就可能不同。不同版本的调度器也有可能不同,不同的编译器实现的运行时也可能不同。所以这就是偶然的行为,你的程序是不可以依赖这种未定义行为的。
    mscb
        11
    mscb  
       2019-04-17 16:43:18 +08:00 via Android
    @Fitz 对,你说的没错。P 是为 m 提供一个上下文队列。不过除了一个 P 以外还有一个全局的 P,当 local P 满了以后,g 会移动到 global P 里面,由于 go 添加的队列时间不同说不定会导致 local 和 global 内的 g 顺序不一致呢。
    Fitz
        12
    Fitz  
    OP
       2019-04-17 16:54:38 +08:00
    @reus @mscb 确实 开了竞态检测 输出就会不同。感谢解答!!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3560 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 00:45 · PVG 08:45 · LAX 16:45 · JFK 19:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.