协程是什么
goroutine是用户态线程,其创建和切换都在用户代码中完成而无需进入操作系统内核,所以其开销要远远小于系统线程的创建和切换;协程有时也被称为绿色线程。绿色线程是由程序的运行时(runtime)维护的线程。每个Go程序启动的时候只有一个对用户可见的协程,我们称之为主协程。一个协程可以开启更多其它新的协程。当一个程序的主协程退出后,此程序也就退出了,即使还有一些其它协程在运行。
协程的状态
- 一个处于阻塞状态的协程不会自发结束阻塞状态,它必须被另外一个协程通过某种并发同步方法来被动地结束阻塞状态。
- 如果一个运行中的程序当前所有的协程都出于阻塞状态,则这些协程将永远阻塞下去,程序将被视为死锁了,然后会崩溃。
- 一个处于睡眠中的(通过调用
time.Sleep
)或者在等待系统调用返回的协程被认为是处于运行状态
协程调度-GMP
M表示系统线程,P表示逻辑处理器(并非上述的逻辑CPU),G表示协程。
- G 的数量:理论上没有数量上限限制的。查看当前G的数量可以使用
runtime. NumGoroutine()
- P 的数量:默认值为运行机器的 CPU 核心数,由启动时环境变量
$GOMAXPROCS
或者是由runtime.GOMAXPROCS()
决定 - M 的数量:go 程序启动时,会设置 M 的最大数量,默认 10000. 但是内核很难支持这么多的线程数,所以这个限制可以忽略。
工作流程:
- M与P关联获取P的本地队列中的G
- 大多数的调度工作是通过逻辑处理器(P)来完成的。 逻辑处理器像一个监工一样通过将不同的处于运行状态协程(G)交给不同的系统线程(M)来执行。
- 一个协程在同一时刻只能在一个系统线程中执行。一个执行中的协程运行片刻后将自发地脱离让出一个系统线程
设计策略:
work stealing
:与M相关联的P中无可运行的G,先从全局队列偷取,若没有从其他线程绑定的P偷取一半的Ghand off
:当本线程因为 G 进行系统调用阻塞时,线程释放绑定的 P,把 P 转移给其他空闲的线程执行。(运行的G会挂在M上)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。