美文网首页
go协程学习笔记

go协程学习笔记

作者: 山里小龙 | 来源:发表于2021-03-25 01:02 被阅读0次

协程本质:

go协程本质上还是用线程来运行代码,只是在多线程上增加了调度器,通过调度器让每一个线程可以执行多个协程。

实现原理:

go协程使用GPM调度模型实现,具体内容如下:

G goroutine协程

P process 调度器,为每一个m分配g,

M machine 对应操作系统的线程,g的真正执行者。

P的数量默认是CPU核数,也可以通过GOMAXPROCS来指定数量,每个P都会维护一个runq队列,用于保存G,P会从队列头获取G交给M执行,执行完后放入到队列尾(如果需要继续执行),通过GPM模型实现了多个协程并行(不是并发)执行,可以最大限度地利用到CPU。

协程优点:

协程相对于多线程有哪些优点呢?

1.上下文切换更轻量

触发go上下文切换有两种场景,1是协作式抢占引起的协程切换,2是锁阻塞\IO阻塞\channel阻塞,两种场景保存的上下文数据结构都是g.sched,它的数据结构如下:

与栈相关的SP和BP寄存器

PC

用于保存函数闭包的上下文,也就是DX寄存器

相比多线程协程切换只需要修改少数寄存器内容,所以更轻量,但一个线程使用到的寄存器总大小非常有限,就算全部内容更新也不会消耗多少资源, 但为什么大部分人都会说协程减少了上下文切换带来的开销? 这里就要看上下文的定义了,如果不仅包括协程执行时所需要的数据,还包括内核态与用户态的切换则这句是对的。

2.节省了内核态与用户态的切换

用户态切换与内核态之间切换一次可能花费1000cycles,线程切换由操作系统内核完成,所以需要从用户态切换到内核态然后再切回用户态,而协程则不需要进行状态的切换。

下面这段话测试结果描述了上下文切换带来的损耗:

Since all the context switching is happening at the application level, we don’t lose the same ~12k instructions (on average) per context switch that we were losing when using Threads. In Go, those same context switches are costing you ~200 nanoseconds or ~2.4k instructions.

摘自:https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html

3.提高了IO类任务的效率?

CPU执行线程是抢占式的,GO协程也是协作抢占式,工作原理都一样,都是为每次执行分配固定的时间片,如果只从这一点看,它们执行io类任务效率不会有多大差别,但实际上产生效果还是有区别的,这个后面会提到。

协程引发的思考

1.操作系统需要支持协程吗?

协程能减少线程切换带来的开销,那操作系统有必要开发一种支持协程的线程吗,或者用其它方式支持协程的API?  如果这样做确实可以降低用户或各语言的开发难度,那这种方案可行吗?或者有必要吗?

个人觉得虽然可行但没必要,这样会提高系统的复杂性,尤其是协程队列的维护,这样的功能更贴近业务应该让各开发语言来实现,而不是底层的操作来实现,那这里又引发了另外一个思考:java需要支持协程吗?

2. java需要支持协程吗?

暂时不会支持,以后可能会有,理由是JAVA的线程池同样也有协程带来的开销减少好处,虽然写协程代码更简洁方便,但JDK1.8开始函数式编程的完善让我们创建线程更快捷了。不过如果JAVA支持协程确实会带来一些执行效果上的改变,例如前面提到的IO类任务,在线程池方案中,只有当前活跃的线程会拿到CPU时间片,如果这些线程是IO类会导致正在排队的其它任务长时间不能执行,这样大大降低了CPU利用率,虽然提高线程池活跃数能解决一部分问题,但还是做不到像协程那样每个任务都能公平分配到时间片,所以JAVA实现协程还是有一点点价值的,同样运行在java虚拟机上的Kotlin就支持协程。

求助:

因本人的知识储备与时间有限,有些问题还需要求助网友:

进程内线程切换会触发内核态与用户态的切换吗?

在网上查资料用户态切到内核态有以下三种情况:

1.当程序使用到系统内核的数据或者程序时就需要进入内核态

2.硬件出现异常,会优先执行系统程序

3.程序出现系统级错误

进程内线程切换一般是时间片用完,这种情况并不属于以上三种,那它会触发内核态与用户态的切换吗

问题知乎地址:https://www.zhihu.com/question/451104554

大家帮忙在知乎上回答这个问题,也可以钉钉我一起讨论:jeff07,当然上面笔记有描述错误也欢迎指正。

名词解释:

协作式抢占:sysmon 协程标记某个协程运行过久, 需要切换出去, 该协程在运行函数时会检查栈标记, 然后主动调用GoSched()让出CPU。

SP:stack pointer register 栈指针寄存器(指向栈顶)

BP: base pointer register  基指针寄存器

DX: 通用寄存器中的数据寄存器

参考:

https://mcll.top/2020/04/14/go%E7%9A%84%E5%8D%8F%E7%A8%8B%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2/

https://www.zhihu.com/question/20862617

参考重要摘要:

相关文章

  • go协程学习笔记

    协程本质: go协程本质上还是用线程来运行代码,只是在多线程上增加了调度器,通过调度器让每一个线程可以执行多个协程...

  • 21. Go 协程

    21. Go 协程 Go 协程是什么? Go 协程是与其他函数或方法一起并发运行的函数或方法。Go 协程可以看作是...

  • 【初探协程】之深入分析Yield原理

    最近在学习协程,目前Php实现协程的方式有yield和swoole扩展,另外可实现协程技术的还有Go语言。本文主要...

  • go的协程并发-channel消息机制

    go的协程并发-channel消息机制 方式一 方式二 go-协程实现方案汇总

  • Go语言学习笔记-Go协程

    并发(concurrency)是指一次处理大量事情的能力。让我们用一个例子来说明。并行(parallelism)指...

  • 随笔33号20180930-go协程小tips

    启动一个新的协程时,协程的调用会立即返回。与函数不同,程序控制不会去等待 Go 协程执行完毕。在调用 Go 协程之...

  • Go语言协程池模型--图数据库(Neo4j)写入

    Go语言协程池

  • Go学习笔记-协程与通道

    协程和通道是 Go 语言作为并发编程语言最为重要的特色之一,初学者可以完全将协程理解为线程,但是用起来比线程更加简...

  • Go协程介绍

    参考自《go专家编程》Go协程所实现的是M:N的线程模型,M个协程运行在N个线程中。 1. MPG模型 Go协程中...

  • golang中线程和协程的区别

    协程 协程,英文名Coroutine。但在 Go 语言中,协程的英文名是:gorutine。它常常被用于进行多任务...

网友评论

      本文标题:go协程学习笔记

      本文链接:https://www.haomeiwen.com/subject/mmokhltx.html