美文网首页
2021/04/07GO语句的执行规则

2021/04/07GO语句的执行规则

作者: 温岭夹糕 | 来源:发表于2021-04-08 13:58 被阅读0次

    1.理解协程是如何被调度的

    java中的线程和系统线程的调度关系为1:1
    go中协程和系统线程的调度关系为M:N,这要得益于他的MPG调度模型


    image.png
    • M,即系统线程
    • P,协程处理器,可以承载若干G,使i这些G适时与M进行对接,相当于中介
    • G,协程,由go关键字创建。G存放于队列中,分为全局的G队列和每个P自己维护的G队列

    因此由于P的存在,当一个正在与某个M对接并运行的G,需要因某个事件(如IO)而暂停运行时,P总是能及时发现并把G与M分离,以释放资源供等待运行的G使用,以此来实现多对多的关系
    而当一个 G 需要恢复运行的时候,调度器又会尽快地为它寻找空闲的计算资源(包括 M)并安排运行。另外,当 M 不够用时,调度器会帮我们向操作系统申请新的系统级线程,而当某个 M 已无用时,调度器又会负责把它及时地销毁掉。
    正因为调度器帮助我们做了很多事,所以我们的 Go 程序才总是能高效地利用操作系统和计算机资源。程序中的所有 goroutine 也都会被充分地调度,其中的代码也都会被并发地运行,即使这样的 goroutine 有数以十万计,也仍然可以如此


    image.png

    go函数什么时候被执行?

    demo

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func main() {
        var wg sync.WaitGroup
        for i := 0; i < 10; i++ {
            go func() {
                defer wg.Done()
                wg.Add(1)
                fmt.Println(i)
            }(i)
        }
        wg.Wait()
    }
    

    go 函数真正被执行的事件,总会与其所属的go语句被执行的事件不同,当程序执行到一条go语句,会先视图从某个存放空闲的G的队列中获取一个G,它只有在找不到空闲G的情况下才会去创建一个新的G

    在拿到一个空闲的G后,GO会视图用这个G去包装当前的那个go函数(即函数中的代码),然后再把这个G追加到某个存放可运行的G的队列中

    正因为是队列,先入先出,因此go函数的执行时间总会滞后于它所属的go语句的执行时间
    并且go语句只关心本身执行完毕,GO程序不会去等待go函数执行,因此若不加waitGroup,我们将看不到任何的输出(因为程序已经执行完了,for语句执行速度很快,当它执行完毕,不添加机制的话,10个包装的协程往往没有得到机会运行)

    相关文章

      网友评论

          本文标题:2021/04/07GO语句的执行规则

          本文链接:https://www.haomeiwen.com/subject/ploukltx.html