xiaohanliang
Golang
Golang
  • review
  • DATA STRUCT
    • Slice
    • Map
    • Lock
    • Chanel
    • Pool
    • Interface
  • SCHEDULE
    • 为什么要设计Go协程
    • GMP都是干什么的
    • 一次完整的调度
    • 什么是G栈
    • P&M剥离
    • 常见的暂停操作
  • OTHERS
    • GC介绍
    • 内存介绍
    • 内存分析
Powered by GitBook
On this page
  • 一句话概括它们的定义
  • G
  • P
  • M
  • 为什么需要P
  • GMP模型下的并发安全问题
  • 后面我们会介绍的内容

Was this helpful?

  1. SCHEDULE

GMP都是干什么的

一句话概括它们的定义

在本篇以及后续的文章中, 我们会大量介绍G/M/P三者之间的交互, 以及go里面各种现象的实现原理. 因此一定要先搞清楚这三者分别是什么

G

G, Goroutine, 代表用户协程. 你定义的所有函数都是在G里面运行的, 包括你定义的go func, 甚至main函数都是在G里面运行的.

但是G怎么运行呢? 协程本身不会运行任何东西, G把函数定义, 函数参数都包装包装, 然后提供一些栈, 包装成一个可以直接拿来运行的结构体, 这就是G的工作

P

P最为明显的一个特点就是P持有一个G队列. 每次我们设置GOMAXPROCS就是在设置P的数量. 没错, P决定了真正并行的数量.

除此之外, P是一个对象复用中心, 里面包含了很多用完了等着下次接着用的结构体, 比如defer结构体, 都是以P为维度的

M

M是一个真正的线程, 操作系统直接管辖的那种, 跟上面二者之间的关系为: 一个P配一个M, 持有一个队列的G, M会把P中队列里的G拿出来运行.

为什么需要P

如果说G是用户定义的Goroutine很好理解, M是系统线程也很好理解, 那么为什么我们一定需要P? P能解决什么问题?

一个最大的问题在于如果现在因为某些问题产生了阻塞(如系统调用), 这些阻塞会导致后面的G无法被执行. 但是我们有了P以后, 我们能做到在系统调用的时候及时解绑P与M, P会带着自己剩下的G另寻一个M来继续执行任务, 这个M可能是新创建的, 也可能是在缓存池里的

GMP模型下的并发安全问题

我们会大量介绍一些并发时的安全问题(如Map,Lock), 想要知道怎样保证安全就要知道, 什么样的两个G是"并行"的, 因为只有并行的G才可能会读取同一块数据.

如上图所示真正能产生争抢的, 只有不同M中正在运行的G才会产生争抢, 如果你的数据是以P为维度的, 也就是说只有本P才能取得, 这种是不会产生争抢的(如Pool里的私有数据区域). 这种情况下才需要上锁, 这是并发安全问题的基本,

后面我们会介绍的内容

  • G

    • G结构体到底包装了那些东西

    • G栈是什么样的? 如果G有栈, 那么栈是怎么扩容的?

  • P

    • 什么叫"对象复用中心"?

    • P是怎么管理所持有的G的?

  • M

    • GMP三者是怎么调度并开始工作的?

    • 为什么会有缓存池里的M这种概念?

Previous为什么要设计Go协程Next一次完整的调度

Last updated 4 years ago

Was this helpful?