教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 golang 所有进程休眠_Golang中Goroutine的调度流程

golang 所有进程休眠_Golang中Goroutine的调度流程

发布时间:2021-04-10   编辑:jiaochengji.com
教程集为您提供golang 所有进程休眠,Golang中Goroutine的调度流程等资源,欢迎您收藏本站,我们将为您提供最新的golang 所有进程休眠,Golang中Goroutine的调度流程资源

首先golang中协程golang是用户线程与系统线程的对应关系是多对多,既能利用多核cpu资源,也能尽可能减少上下文切换成本,代价是go需要实现复杂的goroutine调度机制。

N:1,所有用户线程对应1个系统线程,无法利用多核cpu;

1:1,1个用户线程对应一个系统线程,上下文切换成本高。

调度逻辑

四个结构体

M:Machine,操作系统线程。一个M被创建后会在P空闲队列中获取P进行绑定,未绑定则进入阻塞状态。

P:Process,调度器的核心处理器。通常表示执行上下文,P用于绑定M和G,由GOMAXPROCS指定最大数量,默认数量为cpu核心数。P可以跟多个M绑定,但同一时刻P只绑定在一个M上。

G:Goroutine,用户级线程。

(G0:调度函数的goroutine,go进程创建就会存在,负责调度工作。)

S:Scheduler,全局调度器,维护M、P和G队列,负责调度。

两个队列

本地队列:每个P维护一个本地队列,存放G,当前与P绑定的M若新生成G,会放入本地队列,当本地队列满时会拿出一半的本地队列中的G放入全局队列;

全局队列:存放本地队列溢出的G。调度过程中有1/61的概率检查全局队列,确保全局队列中的G也会被调度。

抢占式调度逻辑:

M绑定的P首先有1/61概率从全局队列获取G,60/61概率从本地队列获取G;

全局队列情况下如果没有获取到G,那么从本地队列获取G;

如果本地队列没有G,那么P从其他P的本地队列窃取G;

如果窃取不到G,那么从全局队列中获取一部分G到本地队列,获取n = min(len(GQ)/GOMAXPROCS 1, len(GQ/2))个;

P获取到G后,绑定的M负责执行G,M必须是运行状态的线程,否则不会真正执行。

调度本质:调度器P将协程G合理地分配到系统线程M上执行。

如果当前的M执行的G调用syscall阻塞,P会与M进行分离,M负责执行阻塞的G,P带着队列中的G绑定到新的M中,继续执行其他G;使得虽然当前G进入阻塞,但并没有影响到P去执行其他G。

M执行的G阻塞操作返回后,由于没有了P,失去切换上下文执行后续逻辑的机会,因此尝试获取新的P去执行,如果获取不到P,M就把当前G放入全局队列等待调度,自己置于休眠状态。

窃取:如果当前M绑定的P中没有可执行的G,那么就会随机从其他P中拿取一般的G放入自己的队列,以提高资源利用率。

线程自旋

线程自旋相对于线程阻塞,表现为循环执行指定的逻辑,而不进入阻塞状态。在go的调度逻辑中,为了实现高性能的并发,如果全局队列和本地队列都为空,绑定P的M没有G可以执行,会进入自旋状态等待新的G,不会进入阻塞状态休眠,减少了M的上下文切换成本。

注意只有绑定了P的M会进入自旋状态,因此最多会有GOMAXPROCS个自旋线程,避免了浪费过多系统资源,其余未绑定的空闲M依然会进入休眠状态。

到此这篇关于“golang 所有进程休眠_Golang中Goroutine的调度流程”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
golang 所有进程休眠_Golang中Goroutine的调度流程
golang 深入浅出之 goroutine 理解
[Go 教程系列笔记] goroutine(协程)
go协程和线程的区别
go test 如何输出到控制台_深度剖析 Go 中的 Go 协程 (goroutines) -- Go 的并发
电脑升级Windows 之后无法正常关机 休眠怎么解决
让你很快就能理解-go的协程调度原理
Go:Goroutine 的切换过程实际上涉及了什么
Golang协程调度原理( G、M、P)
Golang 中的 Goroutine 调度原理与 Chanel 通信

[关闭]
~ ~