GolangRuntime学习

2020-11-28  本文已影响0人  LegendGo

Runtime 简介和发展

Runtime 简介

Golang Runtime 是go语言运行所需要的基础设施

Golang调度简介

理解调度,需要首先理解两个概念:运行和阻塞。特别是在协程中,这两个概念不容易被正确理解。正确的理解我们应该处理事情的时候像是CPU,而不是而不是像线程或者协程. 假如我当前在写某个服务, 发现依赖别人的函数还没有 ready, 那就把写服务这件事放一边. 点开企业微信, 我去和产品沟通一些问题了. 我和产品沟通了一会后, 检查一下, 发现别人已经把依赖的函数提交了, 然后我就最小化企业微信, 切到 IDE, 继续写服务 A 了.

go 在用户态实现调度, 所以 go 要有代表协程这种执行流的结构体, 也要有保存和恢复上下文的函数, 运行队列. 理解了阻塞的真正含义, 也就知道能够比较容易理解, 为什么 go 的锁, channel 这些不阻塞线程.

真正代表协程的是 runtime.g 结构体. 每个 go func 都会编译成 runtime.newproc 函数, 最终有一个 runtime.g 对象放入调度队列. 上面的 func1 函数的指针设置在 runtime.g 的 startfunc 字段, 参数会在 newproc 函数里拷贝到 stack 中, sched 用于保存协程切换时的 pc 位置和栈位置.

协程切换出去和恢复回来需要保存上下文, 恢复上下文, 这些由以下两个汇编函数实现. 以上就能实现协程这种执行流, 并能进行切换和恢复.(下图中的 struct 和函数都做了精简)

GPM模型

数据结构 数量 意义
G Runtime.g运行的函数指针,stack,上下文等 无限制 代表用户的代码执行流
P Runtime.P runs,free g 等 默认是机器的核数 表示执行需要的资源
M Runtime.m 对应一个由clone创建的线程 比P多,最大一万多 代表执行者,底层线程

首先为什么把全局队列打散, 以及 mcache 为什么跟随 P, 这个在 GM 模型那一页就讲的比较清楚了.然后为什么 P 的个数默认是 CPU 核数: Go 尽量提升性能, 那么在一个 n 核机器上, 如何能够最大利用 CPU 性能呢? 当然是同时有 n 个线程在并行运行中, 把 CPU 喂饱, 即所有核上一直都有代码在运行.

在 go 里面, 一个协程运行到阻塞系统调用, 那么这个协程和运行它的线程 m, 自然是不再需要 CPU 的, 也不需要分配 go 层面的内存. 只有一直在并行运行的 go 代码才需要这些资源, 即同时有 n 个 go 协程在并行执行, 那么就能最大的利用 CPU, 这个时候需要的 P 的个数就是 CPU 核数. (注意并行和并发的区别)

调度

golang调度的职责就是为需要执行的Go的代码(G)寻找执行者(M)以及执行的准许和资源(P),并没有一个调度实体,调度是需要发生在带哦度时由m执行runtime.schedule方法进行。

调度的时机

Sysmon 协程

P的数量影响了同时运行GO的协程数,如果P被占用的过久,就会影响调度。sysmon协程的一个功能就是进行抢占

sysmon的协程是在go runtime 初始化后,执行用户编写的代码之前,由runtime的启动不在与任何P的绑定,直接由一个M执行的协程,类似于Linux的一些执行系统任务的内核线程。

网络

用户态的协程:结合epoll,nonblock模式的fd操作,网络操作没有好的时候,切换协程,如果网络请求好了,后把相关协程添加到运行队列。保证网络操作达到既不阻塞线程,又是同步的执行效果

调度综述

内存分配简介

GC简介

三色标记法
  1. 有黑白灰三个集合,初始化所有对象是白色
  2. 从ROOT对象开始标记,并将所有可以达到的对象标记为灰色
  3. 从灰色对象集合中取出对象,将其引用的对象标记为灰色,放入灰色集合,并将自己标记为黑色
  4. 重复第三步,直到灰色集合清空
  5. 标记结束,不可达的白色对象为垃圾对象,对内存进行清扫,并回收空间
  6. 重置GC状态

优化建议

  1. 涉及文件,或是CGO文件较多的程序,可以将P增大
  2. 什么时候需要协程池
    • 主要还是要隔离减少栈的扩容和缩容,大量维持连接的协程不可以不用协程栈
    • 复杂任务使用协程
  3. 全局缓存有大量key的情况下,少用指针
  4. 一点点拷贝胜过传指针
  5. slice 和map 的容量初始化:减少不断的加元素的扩容
  6. Json-iterator 带地encoding/json
  7. 集成gops和开启pprof

Runtime 总结

思想 作用 实例
并行 减少操作的wall time和阻塞
纵向多层次 减少锁竞争和冲突,更加细粒度的锁控制
横向多个class 找到最适配的,减少内存浪费和碎片化
缓存 减少重新申请
缓冲 放入队列,操作异步化
均衡 负载均衡,不会因为work太多而成为瓶颈

总结于知乎:https://zhuanlan.zhihu.com/p/95056679

上一篇 下一篇

猜你喜欢

热点阅读