go语言为什么这么依赖gopath这个环境变量GOPATH是你的工作目录,对于项目文件而言,项目的结构和你的工作目录的结构有很大关系 。
GOPATH路径下默认是有以下三个目录的,
1.src 存放源代码(比如:.go .c .h .s等)
2.pkg 编译后生成的文件(比如:.a)
3.bin 编译后生成的可执行文件(为了方便,可以把此目录加入到 $PATH 变量中,如果有多个gopath , 那么使用${GOPATH//://bin:}/bin添加所有的bin目录)
【golang详解】go语言GMP(GPM)原理和调度Goroutine调度是一个很复杂的机制,下面尝试用简单的语言描述一下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做不同的处理:
如果有空闲的P , 则获取一个P,继续执行G0 。
如果没有空闲的P,则将G0放入全局队列,等待被其他的P调度 。然后M0将进入缓存池睡眠 。
如下图
GOMAXPROCS设置P的数量,最多有GOMAXPROCS个线程分布在多个CPU上同时运行
在Go中一个goroutine最多占用CPU 10ms,防止其他goroutine被饿死 。
具体可以去看另一篇文章
【Golang详解】go语言调度机制 抢占式调度
当创建一个新的G之后优先加入本地队列,如果本地队列满了 , 会将本地队列的G移动到全局队列里面,当M执行work stealing从其他P偷不到G时,它可以从全局G队列获取G 。
协程经历过程
我们创建一个协程 go func()经历过程如下图:
说明:
这里有两个存储G的队列 , 一个是局部调度器P的本地队列、一个是全局G队列 。新创建的G会先保存在P的本地队列中,如果P的本地队列已经满了就会保存在全局的队列中;处理器本地队列是一个使用数组构成的环形链表,它最多可以存储 256 个待执行任务 。
G只能运行在M中,一个M必须持有一个P,M与P是1:1的关系 。M会从P的本地队列弹出一个可执行状态的G来执行,如果P的本地队列为空,就会想其他的MP组合偷取一个可执行的G来执行;
一个M调度G执行的过程是一个循环机制;会一直从本地队列或全局队列中获取G
上面说到P的个数默认等于CPU核数,每个M必须持有一个P才可以执行G,一般情况下M的个数会略大于P的个数,这多出来的M将会在G产生系统调用时发挥作用 。类似线程池,Go也提供一个M的池子,需要时从池子中获取,用完放回池子 , 不够用时就再创建一个 。
work-stealing调度算法:当M执行完了当前P的本地队列队列里的所有G后,P也不会就这么在那躺尸啥都不干,它会先尝试从全局队列队列寻找G来执行,如果全局队列为空 , 它会随机挑选另外一个P , 从它的队列里中拿走一半的G到自己的队列中执行 。
推荐阅读
- ppt屏幕怎么换,ppt切换怎么换颜色
- 能搭载鸿蒙系统的平板,搭载鸿蒙系统的平板电脑
- postgresql求比例保留的简单介绍
- linux宏命令编辑 linux常用命令编辑
- c语言判断scanf返回值,scanf函数返回
- chatgpt设计建模,tsp建模
- 韩国女直播素材,直播素材大全免费
- java局域网聊天源代码 java局域网联机
- jquery1.12.1.js下载,jquery1124minjs下载