[技术向] 高级语言特性 (Go)
官方资料:
CSP
CSP 全称是通信顺序进程 (Communicating Sequential Processes), 来源于 1978 年 ACM 上的一篇论文, 它指出一门编程语言应该重视 input 和 output 的原语, 尤其是在处理并发问题.
并发场景需要考虑三个基本问题: 原子性, 可见性, 有序性.
CSP 提出了一种并发哲学: 不要通过共享内存来通信, 而是通过通信来实现共享内存, 在 Go 里面, 对应的实现就是 chan 机制.
GMP
G、P、M 三者的含义如下:
G: Goroutine, 每个 goroutine 对应一个 G 结构体, 存储着运行堆栈、状态以及任务函数. G 是用户级线程, 但它不是执行体, 需要绑定到 P 才能被调度执行, 这也是用户级线程的意义所在, 操作系统感知不到 G, 其调度完全由 Go Runtime 负责.
P: Processor, 逻辑处理器. 对 G 来说, P 相当于逻辑上的 CPU 核, 而对 M 来说, P 提供了相关的执行环境, 如内存分配状态、任务队列等, P 的数量限制了系统内最大可并行的 G 的数量 (前提是物理 CPU 核数大于 P 的数量), 这个值由用户设置的
GOMAXPROCS 决定, 最大为 256.M: Machine, 操作系统的内核级线程抽象, 代表真正执行计算的资源. M 并不保留 G 状态, 这是 G 可以跨 M 调度的基础, M 的数量是不定的, 由 Go Runtime 调整. 为了防止创建过多线程导致操作系统调度过于频繁, 有一个默认的最大值.
G、P、M 的结构:

本地队列和全局队列用于辅助 M 对 G 进行调度.
当 G 因系统调用阻塞时 (在 Go Runtime 的可见范围之外), M 也会阻塞, 此时 P 会和 M 解绑, 并寻找新的可用的 M, 若没有可用的 M 就会新建一个 M
当 G 因 channel 或者 network I/O 阻塞时 (在 Go Runtime 的可见范围之内), 不会阻塞 M, M 会寻找其他就绪的 G; 当阻塞的 G 恢复后会重新进入 P 队列等待执行