go语言获取当前可用线程 golang 获取进程信息

golang的线程模型——GMP模型内核线程(Kernel-Level Thread,KLT)
轻量级进程(Light Weight Process,LWP):轻量级进程就是我们通常意义上所讲的线程,由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核线程,才能有轻量级进程
用户线程与系统线程一一对应,用户线程执行如lo操作的系统调用时,来回切换操作开销相对比较大
多个用户线程对应一个内核线程,当内核线程对应的一个用户线程被阻塞挂起时候 , 其他用户线程也阻塞不能执行了 。
多对多模型是可以充分利用多核CPU提升运行效能的
go线程模型包含三个概念:内核线程(M),goroutine(G),G的上下文环境(P);
GMP模型是goalng特有的 。
P与M一般是一一对应的 。P(上下文)管理着一组G(goroutine)挂载在M(内核线程)上运行,图中左边蓝色为正在执行状态的goroutine,右边为待执行状态的goroutiine队列 。P的数量由环境变量GOMAXPROCS的值或程序运行runtime.GOMAXPROCS()进行设置 。
当一个os线程在执行M1一个G1发生阻塞时,调度器让M1抛弃P , 等待G1返回,然后另起一个M2接收P来执行剩下的goroutine队列(G2、G3...),这是golang调度器厉害的地方,可以保证有足够的线程来运行剩下所有的goroutine 。
当G1结束后,M1会重新拿回P来完成,如果拿不到就丢到全局runqueue中,然后自己放到线程池或转入休眠状态 。空闲的上下文P会周期性的检查全局runqueue上的goroutine,并且执行它 。
另一种情况就是当有些P1太闲而其他P2很忙碌的时候,会从其他上下文P2拿一些G来执行 。
详细可以翻看下方第一个参考链接,写得真好 。
最后用大佬的总结来做最后的收尾————
Go语言运行时 , 通过核心元素G,M,P 和 自己的调度器,实现了自己的并发线程模型 。调度器通过对G,M,P的调度实现了两级线程模型中操作系统内核之外的调度任务 。整个调度过程中会在多种时机去触发最核心的步骤 “一整轮调度”,而一整轮调度中最关键的部分在“全力查找可运行G”,它保证了M的高效运行(换句话说就是充分使用了计算机的物理资源),一整轮调度中还会涉及到M的启用停止 。最后别忘了,还有一个与Go程序生命周期相同的系统监测任务来进行一些辅助性的工作 。
浅析Golang的线程模型与调度器
Golang CSP并发模型
Golang线程模型
【golang详解】go语言GMP(GPM)原理和调度Goroutine调度是一个很复杂go语言获取当前可用线程的机制go语言获取当前可用线程,下面尝试用简单的语言描述一下Goroutine调度机制,想要对其有更深入的了解可以去研读一下源码 。
首先介绍一下GMP什么意思:
G ----------- goroutine: 即Go协程,每个go关键字都会创建一个协程 。
M ---------- thread内核级线程,所有的G都要放在M上才能运行 。
P ----------- processor处理器,调度G到M上,其维护了一个队列,存储了所有需要它来调度的G 。
Goroutine 调度器P和 OS 调度器是通过 M 结合起来的,每个 M 都代表了 1 个内核线程,OS 调度器负责把内核线程分配到 CPU 的核上执行
模型图:
避免频繁的创建、销毁线程,而是对线程的复用 。
1)work stealing机制
当本线程无可运行的G时,尝试从其他线程绑定的P偷取G,而不是销毁线程 。
2)hand off机制
当本线程M0因为G0进行系统调用阻塞时,线程释放绑定的P,把P转移给其他空闲的线程执行 。进而某个空闲的M1获取P,继续执行P队列中剩下的G 。而M0由于陷入系统调用而进被阻塞,M1接替M0的工作,只要P不空闲,就可以保证充分利用CPU 。M1的来源有可能是M的缓存池,也可能是新建的 。当G0系统调用结束后,根据M0是否能获取到P,将会将G0做不同的处理:

推荐阅读