P&M剥离
常见的一些系统调用函数如syscall.Chown()
本质上是调用syscall()
的函数完成的, 在go语言中执行一次系统调用包含准备工作+调用+收尾工作三步.
准备工作是指保存现场(详细的说就是pc/sp指针), 同时将P+G的状态从RUNNING调整成SYSCALL的状态, 然后最重要的是确保监控协程sysmon正在运行("什么是sysmon呀?")
Ok, 整理一下现场, M被派去执行G的系统调用任务, P在旁边围观. 我们都知道系统调用时间可能很长, 太长了以至于把P放在那边看都有点不合适了, 这就相当于P无所事事. 但是问题是系统调用时间要多长你知不知道?
如果事先知道就耗时很短
调用结束直接回来当做什么都没发生过
如果事先就知道耗时很长
不能把P放在这里就这么等着, 于是经典场面再放送: P_handoff! 我们会在系统调用一开始的时候就直接把P摘下来
如果P中有任务, 唤醒一个M来执行这个任务. 如果P中无任务, 放到P空闲池内
抱歉, 不知道, 以为很短没想到花了这么长时间
sysmon上场了, sysmon是一个监控线程, 如果它发现你这个调用怎么花了这么长时间, 会帮你把P摘下来
所以sysmon很重要, 如果你一个系统调用花了这么久, 然后你P里的任务都没执行, 那就糟了
所以等你回来的时候, (时间很短的话)可能M手上还有P, (时间很久的话)M手上就没有P了, 因为自己主动交走了, 或者被sysmon强制搞走了.
找找看之前关联的P, 看看这个能不能用, 也许被摘走了但是没被别的M占用
如果之前的用不了, 尝试找找看空闲池里有没有能用的
如果这个M真倒霉到最后也没能找到一个P, 准备休眠吧, 但是自己手上还有一个刚刚系统调用回来的G, 这时候会把这个G放到全局队列里, 然后自己休眠去了.
Last updated
Was this helpful?