设为首页 加入收藏

TOP

深度解密Go语言之 scheduler(四)
2019-09-04 00:56:26 】 浏览:161
Tags:深度 解密 语言 scheduler
的 goroutine 切换,大大提高了效率。

The ability to turn IO/Blocking work into CPU-bound work at the OS level is where we get a big win in leveraging more CPU capacity over time.

Go scheduler 像一个非常苛刻的监工一样,不会让一个 M 闲着,总是会通过各种办法让你干更多的事。

In Go, it’s possible to get more work done, over time, because the Go scheduler attempts to use less Threads and do more on each Thread, which helps to reduce load on the OS and the hardware.

scheduler 的陷阱

由于 Go 语言是协作式的调度,不会像线程那样,在时间片用完后,由 CPU 中断任务强行将其调度走。对于 Go 语言中运行时间过长的 goroutine,Go scheduler 有一个后台线程在持续监控,一旦发现 goroutine 运行超过 10 ms,会设置 goroutine 的“抢占标志位”,之后调度器会处理。但是设置标志位的时机只有在函数“序言”部分,对于没有函数调用的就没有办法了。

Golang implements a co-operative partially preemptive scheduler.

所以在某些极端情况下,会掉进一些陷阱。下面这个例子来自参考资料【scheduler 的陷阱】。

func main() {
    var x int
    threads := runtime.GOMAXPROCS(0)
    for i := 0; i < threads; i++ {
        go func() {
            for { x++ }
        }()
    }
    time.Sleep(time.Second)
    fmt.Println("x =", x)
}

运行结果是:在死循环里出不来,不会输出最后的那条打印语句。

为什么?上面的例子会启动和机器的 CPU 核心数相等的 goroutine,每个 goroutine 都会执行一个无限循环。

创建完这些 goroutines 后,main 函数里执行一条 time.Sleep(time.Second) 语句。Go scheduler 看到这条语句后,简直高兴坏了,要来活了。这是调度的好时机啊,于是主 goroutine 被调度走。先前创建的 threads 个 goroutines,刚好“一个萝卜一个坑”,把 M 和 P 都占满了。

在这些 goroutine 内部,又没有调用一些诸如 channeltime.sleep 这些会引发调度器工作的事情。麻烦了,只能任由这些无限循环执行下去了。

解决的办法也有,把 threads 减小 1:

func main() {
    var x int
    threads := runtime.GOMAXPROCS(0) - 1
    for i := 0; i < threads; i++ {
        go func() {
            for { x++ }
        }()
    }
    time.Sleep(time.Second)
    fmt.Println("x =", x)
}

运行结果:

x = 0

不难理解了吧,主 goroutine 休眠一秒后,被 go schduler 重新唤醒,调度到 M 上继续执行,打印一行语句后,退出。主 goroutine 退出后,其他所有的 goroutine 都必须跟着退出。所谓“覆巢之下 焉有完卵”,一损俱损。

至于为什么最后打印出的 x 为 0,之前的文章《曹大谈内存重排》里有讲到过,这里不再深究了。

还有一种解决办法是在 for 循环里加一句:

go func() {
    time.Sleep(time.Second)
    for { x++ }
}()

同样可以让 main goroutine 有机会调度执行。

总结

这篇文章,从宏观角度来看 Go 调度器,讲到了很多方面。接下来连续的 10 篇文章,我会深入源码,层层解析。敬请期待!

参考资料里有很多篇英文博客写得很好,当你掌握了基本原理后,看这些文章会有一种熟悉的感觉,讲得真好!

参考资料

【知乎回答,怎样理解阻塞非阻塞与同步异步的区别】?https://www.zhihu.com/question/19732473/answer/241673170

【从零开始学架构 Reactor与Proactor】https://book.douban.com/subject/30335935/

【思否上 goalng 排名第二的大佬译文】https://segmentfault.com/a/1190000016038785

【ardan labs】https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part1.html

【论文 Analysis of the Go runtime scheduler】http://www.cs.columbia.edu/~aho/cs6998/reports/12-12-11_DeshpandeSponslerWeiss_GO.pdf

【译文传播很广的】https://morsmachine.dk/go-scheduler

【码农翻身文章】https://mp.weixin.qq.com/s/BV25ngvWgbO3_yMK7eHhew

【goroutine 资料合集】https://github.com/ardanlabs/gotraining/tree/master/topics/go/concurrency/goroutines

【大彬调度器系列文章】http://lessisbetter.site/2019/03/10/golang-scheduler-1-history/

【Scalable scheduler design doc 2012】https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw/edit#heading=h.rvfa6uqbq68u

【Go scheduler blog post】https://morsmachine.dk/go-scheduler

【work stealing】https://rakyll.org/scheduler/

【Tony Bai 也谈goroutine调度器】https://tonybai.com/2017/06/23/an-intro-about-goroutine-scheduler/

【Tony Bai 调试实例分析】https://tonybai.com/2017/11/23/the-simple-analysis-of-goroutine-schedule-examples/

【Tony Bai goroutine 是如何工作的】https://tonybai.com/2014/11/15/how-goroutines-work/

【How Goroutines Work】https://blog.nindalf.com/posts/how-goroutines-work/

【知乎回答 什么是阻塞,非阻塞,同步,异步?】https://www.zhihu

首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇golang微服务框架go-micro 入门笔.. 下一篇Golang检测Linux服务器端口占用

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目