教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Goroutine的调度分析(一)

Goroutine的调度分析(一)

发布时间:2022-02-23   编辑:jiaochengji.com
教程集为您提供Goroutine的调度分析(一)等资源,欢迎您收藏本站,我们将为您提供最新的Goroutine的调度分析(一)资源

  golang这个新兴的语言,最关键的就在于goroutine,而goroutine的调度又是golang的核心。可以说,没有goroutine,那么这个语言就会毫无意义,没有发明的必要。为了能够更好的写出高质量的代码,最近学习了goroutine的调度,收获良多。写篇文章总结记录一下。

<h2 id="我的参考资料">我的参考资料</h2>

Analysis of the Go runtime scheduler 一篇分析goroutine的论文,英文的,其实这篇论文写远比很多博客来的通俗易懂,值得一看。
How Goroutines Work这篇博客简略写goroutine和线程的区别,文章底部也有更进一步阅读参考的链接
goroutine与调度器图文并茂的讲了goroutine调度的算法。值得一看。

<h2 id="go-runtime">Go RUNTIME</h2>

  Go Runtime 管理着goroutine的调度以及运行时的垃圾回收,而我们今天所讨论主要是goroutine的调度。
  Go程序会被编译成机器码,因为Go提供了,goroutine、channels、垃圾回收,所以就需要一个runtime的框架来支持这些特性。Go 程序可以被看成两层,一层是用户代码,一层是runtime并且是调用一些管理goroutine, channel, 以及一些其他的高层抽象。任何系统调用都要通过runtime层来配合goroutine的调度。下图展示了go程序、Go runtime、以及操作系统之间的关系。

  runtime记录着每一个goroutine的状态,并且会在一个线程池上来调度这些goroutine。goroutine是和线程分离的但是却需要依靠线程来运行。所以,有效地在线程池上调度goroutine对go程序的运行效率就显得非常重要了。

<h2 id="线程和goroutine的区别">线程和goroutine的区别</h2> <h3 id="内存的消耗">内存的消耗</h3>

  goroutine的创建是不需要的很多内存的,大约2KB栈空间而已,而一个线程一创建就要约1MB内存,一个服务器一个请求创建一个goroutine而没有任何问题,而一个请求创建一个线程则会导致OutOfMemoryError,任何语言用多线程来实现并发都会遇到这个问题。

<h3 id="创建与销毁的代价">创建与销毁的代价</h3>

  线程的创建与销毁代价是比较大的,所以往往弄一个线程池来解决这个问题。而goroutine的创建销毁都比较cheap, 当然,其实可以看成go已经实现了线程池。

<h3 id="切换代价">切换代价</h3>

  当线程阻塞,其他的线程必须被调度过来被阻塞线程的位置,当线程切换,调度器需要保存所有的寄存器,通用寄存器、程序计数器、栈指针还有其他一些乱七八槽的寄存器,这样的切换代价是很高的,尤其是在频繁进行线程切换的情况下。
  而goroutine的切换代价就很低了,只需要保存3个寄存器:程序计数寄存器、栈指针以及DX。所以,goroutine调度的切换代价以及时间是可以忽略不计的。

<h3 id="goroutine是怎么执行的">goroutine是怎么执行的</h3>

  runtime管理调度着所有的goroutine,从出生到死亡。它会分配一些线程,采用多路复用的策略,来执行goroutine。在任何时候,一个线程会执行一个goroutine,如果这个goroutine阻塞了,这个goroutine就会被换出,这个线程就会执行其他的goroutine。因为goroutine是合作式的调度(这里我也不太明白),那么如果一个goroutine不停的循环就会饿死其他的在这个线程上的goroutine。在go1.2中,这个问题已经有所缓解,当进入一个函数后,runtime会不定时的激活调度器,所以一个没有内联函数的循环会被取代。

<h3 id="goroutine阻塞">goroutine阻塞</h3>

  goroutine是轻量级的,并且以下原因中不会造成线程阻塞。

<pre><code class="lang-go hljs">1. 网络输入 2. sleeping 3. channel 操作 4. 通过sync包的阻塞操作 </code></code></pre>

即使产生上万的goroutine,如果它们是以上4种原因阻塞的,也不会造成系统资源的浪费,因为runtime会调度其他的goroutine给这些被多路复用的thread执行。
简单来说,goroutine是在线程之上的轻量级抽象,go的使用者不用解决线程的麻烦,而系统也不会感受到goroutine的存在。

<h3 id="线程和处理器">线程和处理器</h3>

  尽管你不能直接控制runtime创造线程的数量,但是你可以设置系统使用的处理器的核的数量。通过设置GOMAXPROCS,你就可以增加或减少核的数量来改善你程序的性能了。

<h3 id="思考">思考</h3>

  和其他语言一样,避免同时操作共享的内存是很重要的,最好的策略是用channel来实现共享,do not cmmunicate by sharing memory; instead, share memory by communicating.

<link rel="stylesheet" href="http://csdnimg.cn/release/phoenix/production/markdown_views-d4dade9c33.css"/>
到此这篇关于“Goroutine的调度分析(一)”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Goroutine的调度分析(一)
goroutine 调度器
golang 深入浅出之 goroutine 理解
简单理解 Goroutine 是如何工作的
GO 语言之 Goroutine 原理解析
golang面试题分析03_GMP调度器
Goroutine是如何工作的
goroutine与调度器
Goroutine 调度模型猜想
golang并发原理剖析

[关闭]
~ ~