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

2021-04-08  本文已影响0人  温岭夹糕

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

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


image.png

因此由于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个包装的协程往往没有得到机会运行)

上一篇下一篇

猜你喜欢

热点阅读