go语言的GMP模型(协程并发模型),P是go语言本身内部实现的调度器,它是基于协程队列的,协程在调度器面前就类似一个个独立的任务;P一般数量上是处理器内核数。Process本身有调度和创建M的能力,它会调用系统内核方法创建M(M就是内核中轻量级进程),当其中一个M堵塞甚至发生异常了,那么P会调用系统方法创建新的子进程处理,在子进程中是循环获取goroution,也就是对于每一个M进程而言,其执行的伪代码指令:
while(routinelist.size() > 0){
   if(next.task){
      run routinelist[i].task
   }
}
Context通常被称为上下文,在go中,理解为goroutine的运行状态、现场;存在上下层goroutine context的传递,上层goroutine会把context传递给下层goroutine。在网络编程中,当接收到一个网络请求的request,处理request时,可能会在多个goroutine中处理。而这些goroutine可能需要共享Request的一些信息;当request被取消或者超时时,所有从这个request创建的goroutine也要被结束。
1. Context是我们自己来创建和维护的
2. Context创建一般都需要指向传递父节点的上下文对象,所以Context是一个树状结构
go context包不仅实现了在程序单元之间共享状态变量的方法,同时能通过简单的方法,在被调用程序单元外部通过设置ctx变量的值,将过期或撤销等信号传递给被调用的程序单元。在网络编程中,如果存在A调用B的API,B调用C的 API,如果A调用B取消,那么B调用C也应该被取消,通过在A、B、C调用之间传递context,以及判断其状态就能解决此问题。context结构:
// A Context carries a deadline, a cancellation signal, and other values across
// API boundaries.
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
    // Deadline returns the time when work done on behalf of this context
    // should be canceled. Deadline returns ok==false when no deadline is
    // set. Successive calls to Deadline return the same results.<br>      
    // 返回一个超时时间,到期则取消context。在代码中,可以通过 deadline 为io操作设置超时时间
    Deadline() (deadline time.Time, ok bool)
    
    // a Done channel for cancellation. 返回一个channel, 用于接收context的取消或者deadline 
    //信号。当channel关闭,监听done信号的函数会立即放弃当前正在执行的操作并返回。如果 context实 
    //例是不可取消的,那么返回 nil, 比如空 context, valueCtx
    Done() <-chan struct{}
 
    // 返回一个error变量,从其中可以知道为什么context会被取消。
    Err() error
 
    // 让context在goroutine之间共享数据,当然,这些数据需要时协程并发安全的。比如,共享了一个 
    //map,那么这个map的读写要加锁。
    Value(key interface{}) interface{}
}Channel 被设计用来实现协程间通信的组件,其作用域和生命周期不可能仅限于某个函数内部,所以 golang 直接将其分配在堆上,准确地说,你并不需要知道。Golang 中的变量只要被引用就一直会存活,存储在堆上还是栈上由内部实现决定而和具体的语法没有关系。知道变量的存储位置确实和效率编程有关系。如果可能,Golang 编译器会将函数的局部变量分配到函数栈帧(stack frame)上。然而,如果编译器不能确保变量在函数 return (pop压出栈)之后不再被引用,编译器就会将变量分配到堆上。而且,如果一个局部变量非常大,那么它也应该被分配到堆上而不是栈上。当前情况下,如果一个变量被取地址,那么它就有可能被分配到堆上;然而还要对这些变量做逃逸分析,如果函数 return 之后,变量不再被引用,则将其分配到栈上。GO并发通信的模型是通信顺序进程(Communicating Sequential Processes, CSP),借助于内部实现的Channel机制,channel是golang中用来实现多个goroutine通信的管道,它的底层是一个叫做hchan的结构体。在go的runtime包下。
type hchan struct {
   //channel分为无缓冲和有缓冲两种。
   //对于有缓冲的channel存储数据,借助的是如下循环数组的结构
     qcount   uint           // 循环数组中的元素数量
     dataqsiz uint           // 循环数组的长度
     buf      unsafe.Pointer // 指向底层循环数组的指针
     elemsize uint16 //能够收发元素的大小
   
     closed   uint32   //channel是否关闭的标志
     elemtype *_type //channel中的元素类型
   
   //有缓冲channel内的缓冲数组会被作为一个“环型”来使用。
   //当下标超过数组容量后会回到第一个位置,所以需要有两个字段记录当前读和写的下标位置
     sendx    uint   // 下一次发送数据的下标位置
     recvx    uint   // 下一次读取数据的下标位置
   
   //当循环数组中没有数据时,收到了接收请求,那么接收数据的变量地址将会写入读等待队列
   //当循环数组中数据已满时,收到了发送请求,那么发送数据的变量地址将写入写等待队列
     recvq    waitq  // 读等待队列
     sendq    waitq  // 写等待队列
 
     lock mutex //互斥锁,保证读写channel时不存在并发竞争问题
 }结构图如下:

总结hchan结构体的主要组成部分有四个:
- 用来保存goroutine之间传递数据的循环链表。=> buf。
- 用来记录此循环链表当前发送或接收数据的下标值。=> sendx和recvx。
- 用于保存向该chan发送和从改chan接收数据的goroutine的队列。=> sendq 和 recvq
- 保证channel写入和读取数据时线程安全的锁。 => lock



















