Go 分布式学习利器(17)-- Go并发编程之协程机制:Grountine 原理及使用
文章目录
- 1. Thread VS Groutine
- 2. Groutine 调度原理
- 3. Groutine 示例代码
关于Go的底层实现还需要后续持续研究,文中如有一些原理描述有误,欢迎指证。
1. Thread VS Groutine
这里主要介绍一下Go的并发协程相比于传统的线程 的不同点:
创建时默认的stack大小
JDK5 以后Java thread stack默认大小为1M
C++ 的thread stack 默认大小为8M
Grountine 的 Stack初始化大小为2K所以Grountine 大批量创建的时候速度会更快
和 KSE(Kernel Space Entity即内核线程)的对应关系
Java Thread是1:1
Groutine 是M:N,多对多,如下图。
内核线程是由CPU直接调度,如果一个用户线程对应一个内核线程,调度效率来看肯定是快于多个用户线程对应一个内核线程的。然而,实际的开发环境中一个用户线程对应一个内核线程 在 高并发场景下出现的频繁内核线程上下文切换(保留线程上下文,更新CPU内部各种寄存器)对系统性能的影响占主要部分。而Go语言内部实现的线程调度器提供了多个用户线程和一个内核线程对应,这样在高并发场景能够有效降低线程间切换带来的性能消耗。
当然,如果如果仅仅只有几个或者十几个(小于CPU核数)用户线程的应用可能就体现不出Grountine的优势了。
2. Groutine 调度原理
如下图:
- 编号1: 没有被用户线程使用的内核线程
- 编号2: Go自实现的协程调度器P 对应一个内核线程M0。在该调度器中维护了一个协程队列,一个时刻可以有一个协程正在运行G0,其他的协程在调度队列中等待被执行。
- 编号3: 协程处理器没有正在执行的协程,可以从调度队列中取出一个协程
- 编号4: 协程可以通过系统调用来和内核线程绑定
问题1:如果一个正在运行的G协程将Processor 独占时间较久,导致后续排队的协程一直无法运行,Processor如何处理?
Go 运行之后,后台会维护一个守护线程来进行计数 ,表示一个Processor 完成的协程数量。当一段时间发现这个计数没有更新,会向当前正在执行的协程任务栈插入一个flag,协程运行时遇到非inline函数时会读取到这个标记,会将正在运行的自己中断并插入到等待Processor调度的队尾,Processor此时会继续调度其他的协程进行运行。
问题2: 当一个协程(内核线程的执行)被系统中断(CPU需要调度I/O线程),Processor会有什么样的行为?
Processor并不会就此等待中断处理完成,而是为了保证并发,将自己和另一个内核线程绑定,继续执行调度队列中的等待被执行的协程。当中断的协程被唤醒,则会将自己加入到另一个Processor的等待队列或者全局等待队列中。
当一个协程被中断,它在CPU寄存器中的状态会被保存在自己的协程对象中,重新获得执行机会时这一些状态会被写入到新的寄存器中继续运行。
通过以上调度可以看到,Groutine能够在不同的场景下仍然希望保持较高的并发继续执行来保证自己的高并发性能。
3. Groutine 示例代码
启动一个Groutine非常简单
go func(){}()
的方式
测试代码如下, 注意使用方法一的值传递方式启动go routine 。
package groutine_testimport ("fmt""testing""time"
)func TestGroutine(t *testing.T) {for i := 0; i < 10; i ++ {// 方法一: 正确go func(i int) { // 启动 一个 go routinefmt.Println(i)}(i)// 方法二:错误// 如下代码是有问题的// i 地址是被所有协程共享的,这个时候打印的结果// 会受到其他协程的影响// 想要保证代码的正确性,即每一个go routine打印// 各自的i 值,需要利用如上启动go routine的代码,// 进行值传递,从而让每个goroutine 独享各自的i的地址。// go func() {// fmt.Println(i)// }()}time.Sleep(time.Millisecond*50)
}
Go 分布式学习利器(17)-- Go并发编程之协程机制:Grountine 原理及使用相关推荐
- Golang并发编程-GPM协程调度模型原理及组成分析
文章目录 一.操作系统的进程和线程模型 1.1.基础知识 1.2.KST/ULT 二.Golang的GPM协程调度模型 三.M的结构及对应关系 四.P的结构及状态转换 五.G的结构及状态转换 六.GP ...
- python并发编程之协程
python并发编程之协程 1.协程: 单线程实现并发 在应用程序里控制多个任务的切换+保存状态 优点: 应用程序级别速度要远远高于操作系统的切换 缺点: 多个任务一旦有一个阻塞没有切,整个线程都阻塞 ...
- java future_Java并发编程之异步Future机制的原理和实现
Java并发编程之异步Future机制的原理和实现 项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们 ...
- python并发编程:协程asyncio、多线程threading、多进程multiprocessing
python并发编程:协程.多线程.多进程 CPU密集型计算与IO密集型计算 多线程.多进程与协程的对比 多线程 创建多线程的方法 多线程实现的生产者-消费者爬虫 Lock解决线程安全问题 使用线程池 ...
- 学习笔记:Java 并发编程②_管程
若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 配套资料: ...
- Java并发编程实战~协程
Golang 是一门号称从语言层面支持并发的编程语言,支持并发是 Golang 一个非常重要的特性.在上一篇文章<44 | 协程:更轻量级的线程>中我们介绍过,Golang 支持协程,协程 ...
- python并发之协程_python并发编程之协程
一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...
- 3-Go并发编程与协程Goroutine
目录 一.并发编程 1 - 并行和并发 2 - 程序.进程.线程 3 - 进程并发 4 - 线程并发 5 - 线程同步 二.协程Coroutine 1 - 协程概念 2 - Go并发 3 - go程创 ...
- 学习笔记:Java 并发编程①_基础知识入门
若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 视频下载: ...
最新文章
- 世界物联网大会IOT
- 如何为file增加文件类型的识别
- 杭电1325java实现
- 【spring-session】介绍
- adsl拨号无公网地址如何用ddns_【好玩的网络-第5期】分享自编ddns程序,17行代码轻松实现免费ddns,服务器或nas玩家的福音...
- 操作系统以什么方式组织用户使用计算机,操作系统习题
- WPF自定义控件与样式(1)-矢量字体图标(iconfont)
- 猎豹MFC--图片控件CStatic和动画控件CAnimateCtrl
- 各种格式PPC手机软件的安装方法
- 魔兽支持宽屏--怎样让宽屏支持更多游戏?
- Cocos2d-x 中文标题设置
- FeynRules的上手使用1--介绍模型参数设置
- 程序员专属表情包,正在疯传中!
- 物联网开发笔记(62)- 使用Micropython开发ESP32开发板之控制ILI9341 3.2寸TFT-LCD触摸屏进行LVGL图形化编程:环境搭建
- linux查看电脑耗电量,命令行 - 在Linux上,观察程序耗电量使用的最佳方法是什么?...
- SAP SD基础知识之免费货物(Free Goods)
- 系统提示服务器错误 请联系管理员,金蝶软件K3 主控台登录提示:应用服务器连接到一个错误的数据库,请与系统管理员联系...
- 自问自答——使用视图能提高查询效率么?
- 全球与中国电机市场深度研究分析报告
- 阿里感悟- 沟通能力
热门文章
- leetcode解题文件夹
- XML和JSON数据格式对比
- linux定时器(crontab)实例
- install python+twisted+mysqldb+django on mac
- 关于css中float的一切
- 用js 判断datagrid 中的 checkbox 是否被选中
- unity课设小游戏_Unity制作20个迷你小游戏实例训练视频教程
- mysql dump 到的文件_mysql查询结果导出到文件
- python实现洗牌算法_为什么渔民耶茨最有用的洗牌算法?
- android 自定义loading,Android自定义动画-StarLoadingView