Goroutine在代码层面表现为与其他函数或方法同时运行的函数或方法,Goroutine可以被看作是简化版的线程。

Goroutine并不是线程

goroutine是Go语言调度器中待执行的任务,它在运行时调度器中的地位与线程在操作系统中差不多,但是goroutine占用的内存空间更小,上下文切换的开销也较小。
goroutine只存在于Go语言运行时,它是Go语言在用户态提供的线程,作为一种粒度更细的资源调度单元,如果使用得当能够在高并发的场景下更搞笑地利用机器的CPU。
多个线程可以属于同一个进程并共享内存空间。Go语言调度器通过使用与CPU数量相等的线程减少线程频繁切换的内存开销,同时在每一个线程上执行额外开销更低的goroutine来降低操作系统和硬件的负载

  1. thread
  2. | |
  3. |------ ----|
  4. | |
  5. goroutine1 goroutine2

G-M-P模型

Go 1.14之后的版本采用任务窃取行的调度器,概括为运行时G-M-P模型,调度器将每一个线程绑定到了独立的CPU上,这些线程会被不同处理器管理。

  • G: goroutine

主要保存goroutine的一些状态信息以及CPU的一些寄存器值,以便于调度器切换到该goroutine时,CPU直到从哪一条指令开始继续执行。
goroutine是一个待执行的任务,其包含三种状态:

  • 等待中:goroutine正在等待某些条件满足
  • 可运行:goroutine已经准备就绪,可以在线程运行
  • 运行中:goroutine正在某个线程上运行

image.png

  • M: 表示操作系统的线程

M由操作系统的调度器调度和管理,G需要被调度到M上才能运行。
最多只会有GOMAXPROCS个活跃的线程能够正常运行,默认情况下,GOMAXPROCS的值与机器的核数相等。

  • P: 处理器

可以被看做运行在线程上的本地调度器。
P是线程和goroutine的中间层,能够提供线程需要的上下文环境,也会负责调度线程上的等待队列,通过处理器P的调度,每一个内核线程都能够执行多个goroutine,它能够在goroutine进行一些I/O操作时及时切换,提高线程的利用率。

  • WSS: 工作窃取制度

M切换出G后,将其插入本地队列尾部
本地队列为空时从其他队列尾部偷取G
都没有则去偷全局队列
没有工作则休眠