• Golang(三)Goroutine原理


    前言

    • 最近用到了一些 Golang 异步编程的地方,感觉 Golang 相对于其他语言(如 Java)对多线程编程的支持非常大,使用起来也非常方便。于是决定了解一下 Goroutine 的底层原理。
    • Goroutine 本质是协程,是实现并行计算的核心。只需要在对应的函数前加上 Go 关键词即可异步执行:
    go func() {
    }()

    基本概念

    • 并发:一段时间内执行多个程序,即在一个 cpu 上切换着执行多项任务,宏观上是同时的,微观上是顺序执行
    • 并行:同时执行多个程序,即在多个 cpu 上同时运行不同任务,不需要上下文切换执行不同任务达到宏观同时进行的效果
    • 进程:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。是具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体
    • 线程:线程是进程的一个实体,是 cpu 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换较快,资源开销较少
    • 协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作执行者则是用户自身程序。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。Goroutine 就是一种协程

    调度模型

    • Goroutine 并发调度通过 GPM 模型实现,包含四个结构:M、G、P、Sched:
      • M:代表内核级线程,一个 M 对应一个线程
      • G:代表一个 Goroutine,包含自己的栈、程序计数器等信息
      • P:指处理器,主要用途是用来执行 Goroutine,维护一个 Goroutine 队列,同时还有一个全局队列。每一个运行的 M 都必须绑定一个 P,就像线程必须在么一个 cpu 核上执行一样
      • Sched:代表调度器,维护 M 和 G 的队列和状态信息

    • 如上图,2 个 M,每个 M 拥有 1 个 P 和 1 个正在运行的 G。
    • P 的数量可以通过 GOMAXPROCS() 设置,代表有多少个 Goroutine 可以同时运行。

    调用异步

    • 执行 go func() 时,会在队列尾部加入一个 Goroutine。
    • 如果此时还有空闲的 P,则创建一个 M。M 会启动一个底层线程,循环执行能找到的 G 任务。
    • G 任务的执行任务是:先从本地队列找,本地没有则从全局队列找。一次转移 num(G)/num(P) 个任务,再去其他 P 中获取队列一半的任务。

    监视超时

    • 启动一个 G 时,会专门创建一个 Sysmon,用来监视和管理。记录所有 P 的 G 任务计数 schedtick(schedtick 会在每执行一个 G 任务后递增)。
    • 如果检查到 schedtick 一直没有递增,说明这个 P 一直在执行同一个 G 任务,如果超过一定时间(10ms),就在这个 G 任务的栈信息里加一个标记。
    • 内联函数执行时发现标记则中断自己,把自己加到队列末尾;非内联函数则会忽视标记,一直执行到结束。

    中断恢复

    • 对于一个 G 任务中断后:中断时将寄存器信息保存在 G 对象里,再次执行时将栈信息复制到寄存器里,继续执行。

    首次启动

    • 系统启动时主线程启动,第一个 M1 就是主线程,M1 会绑定一个 P。
    • main 函数作为第一个 Goroutine 执行。
    • main 里其他的 Goroutine 会绑定到当前 M1 的 P1 上。
    • 执行 main 里的 Goroutine 时,会创建新的 M2,新 M2 的初始 P2 本地任务队列时空的,会从 P1 取一些过来。
    • 然后依此类推直到 M 数量达到限制。

    参考文献

  • 相关阅读:
    spring security 单一账户多地方登陆提醒, ajax 拦截器 Interceptor
    Maven 项目打包发布
    jQuery使用on()绑定动态生成元素的事件无效
    ie下li标签中span加float:right不换行问题解决方案
    IE使用多彩文档上传数据库报错
    对象数组中删除指定元素
    jquery 文本框内容清空
    SQL删除重复数据方法
    静态数据的初始化
    java变量初始化顺序
  • 原文地址:https://www.cnblogs.com/wangao1236/p/10899028.html
Copyright © 2020-2023  润新知