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 数量达到限制。
参考文献
Golang(三)Goroutine原理的更多相关文章
- 谈谈Golang中goroutine的调度问题
goroutine的调度问题,同样也是我之前面试的问题,不过这个问题我当时并不是很清楚,回来以后立马查阅资料,现整理出来备忘. 有一些预备知识需要说明,就是操作系统中的线程.操作系统中的线程分为两种: ...
- [转]golang的goroutine调度机制
golang的goroutine调度机制 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 一直对goroutine的调度机制很好奇最近在看雨痕的golang源码分析基于go ...
- golang的goroutine与channel
Golang的goroutine是非抢占式的, 令人相当蛋疼! 有痛不能呻吟...只能配合channel在各goroutine之间传递信号来实现抢占式, 而这形成了golang最灵活与最具性能的核心. ...
- 机器学习之决策树三-CART原理与代码实现
决策树系列三—CART原理与代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/9482885.html ID ...
- go语言之行--golang核武器goroutine调度原理、channel详解
一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...
- Golang/Go goroutine调度器原理/实现【原】
Go语言在2016年再次拿下TIBOE年度编程语言称号,这充分证明了Go语言这几年在全世界范围内的受欢迎程度.如果要对世界范围内的gopher发起一次“你究竟喜欢Go的哪一点”的调查,我相信很多Gop ...
- Golang Context 的原理与实战
本文让我们一起来学习 golang Context 的使用和标准库中的Context的实现. golang context 包 一开始只是 Google 内部使用的一个 Golang 包,在 Gola ...
- Golang控制goroutine的启动与关闭
最近在用golang做项目的时候,使用到了goroutine.在golang中启动协程非常方便,只需要加一个go关键字: go myfunc(){ //do something }() 但是对于一些长 ...
- golang slice 切片原理
golang 中的 slice 非常强大,让数组操作非常方便高效.在开发中不定长度表示的数组全部都是 slice .但是很多同学对 slice 的模糊认识,造成认为golang中的数组是引用类型,结果 ...
随机推荐
- 12、Render函数
1.什么是Render函数 Vue 推荐在绝大多数情况下使用模板来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编程的能力.这时你可以用渲染函数,它比模板更接近编译器. ...
- Bootstrap4后台导航栏制作
<!Doctype html> <html lang="zh-cn"> <head> <!-- Required meta tags -- ...
- python--进程初识详解
进程:通俗理解一个运行的程序或者软件,进程是操作系统资源分配的基本单位 1.1.导入进程模块 import multiprocessing 1.2.Process进程类的语法结构如下: Process ...
- uni-app项目记录
1.如何定义一个全局属性 在App.vue 文件中,以 global.属性名= XXX; 定义 在其他页面就以 global.属性名来调用 或者在min.js 中使用 Vue.prototype 挂载 ...
- 安恒Red Team 内部红蓝对抗框架
0x00 准备钓鱼攻击(从公开资源) 1.常见的红队攻击向量和技术 2.常见的蓝队侦查和预防控制 0x02 发送钓鱼邮件(到目标组织员工邮箱地址) 1.常见的红队攻击向量和技术 2.常见的蓝 ...
- SqlServer数据库优化之索引、临时表
问题:工作是查询一张500万多条数据的表时,查询总是很慢,于是进行优化. --查询表所有索引 use RYTreasureDB EXEC Sp_helpindex [RecordDrawScore] ...
- Python 基础总结篇
变量及数据类型 Numbers数字分为:int整型,long长整型,float浮点型,complex复数 String字符串由数字.字母.下划线组成的一串字符,用于表示文本的数据类型 bool布尔型: ...
- Python可视化查看数据集完整性: missingno库(用于数据分析前的数据检查)
数据分析之前首先要保证数据集的质量,missingno库提供了一个灵活易用的可视化工具来观察数据缺失情况,是基于matplotlib的,接受pandas数据源 快速开始 样例数据使用 NYPD Mot ...
- nginx无网络启动失败——proxy_pass域名DNS解析出错
问题: nginx启动或者reload的时候,会对proxy_pass后面的域名进行DNS解析,如果解析失败,启动就会失败或者reload失败. 我们是to B的产品,客户的环境可能是不通公网的,因此 ...
- SpringBoot整合JavaWeb
一.SpringBoot整合Servlet的两种方式 1.通过注解扫描完成Servlet组件的注册 编写Servlet package com.example.demo.servlet; import ...