go语言调用栈 go语言调用c接口( 二 )


Background返回一个非空的Context 。它永远不会被取消 。它通常用来初始化和测试使用 , 作为一个顶层的context,也就是说一般我们创建的context都是基于Background 。
TODO返回一个非空的Context 。当不清楚要使用哪个上下文的时候可以使用TODO 。
他们两个本质上都是emptyCtx结构体类型 , 是一个不可取消,没有设置截止时间,没有携带任何值的Context 。
有了如上的根Context , 那么是如何衍生更多的子Context的呢?这就要靠context包为我们提供的With系列的函数了 。
通过这些函数,就创建了一颗Context树,树的每个节点都可以有任意多个子节点,节点层级可以有任意多个 。
WithCancel函数,最常用的派生 context 方法 。该方法接受一个父 context 。父 context 可以是一个 background context 或其他 context 。
WithDeadline函数,该方法会创建一个带有 deadline 的 context 。当 deadline 到期后 , 该 context 以及该 context 的可能子 context 会受到 cancel 通知 。另外,如果 deadline 前调用 cancelFunc 则会提前发送取消通知 。
WithTimeout和WithDeadline基本上一样,这个表示是超时自动取消 , 是多少时间后自动取消Context的意思 。
WithValue函数和取消Context无关 , 它是为了生成一个绑定了一个键值对数据的Context,这个绑定的数据可以通过Context.Value方法访问到,一般我们想要通过上下文来传递数据时,可以通过这个方法,如我们需要tarce追踪系统调用栈的时候 。
使用Context的程序应遵循以下规则,以使各个包之间的接口保持一致:
1.不要将 Context 塞到结构体里 。直接将 Context 类型作为函数的第一参数 , 而且一般都命名为 ctx 。
2.不要向函数传入一个 nil 的 context,如果go语言调用栈你实在不知道传什么 , 标准库给你准备好了一个 context:todo 。
3.不要把本应该作为函数参数的类型塞到 context 中,context 存储的应该是一些共同的数据 。例如:登陆的 session、cookie 等 。
4.同一个 context 可能会被传递到多个 goroutine,别担心,context 是并发安全的 。
【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将进入缓存池睡眠 。

推荐阅读