Golang协程及其底层剖析

协程

线程本身占用资源大,操作和切换开销大
其实多个协程复用了一个线程,这样就减少了线程的开销

  1. 协程的底层

stack(lo ,hi)指向高地址和低地址
其中栈是为了记录协程执行到哪里了
sched(sp 栈指针,指向执行到哪个方法了
pc ,指向具体执行到哪一行代码了)
goid
status状态
m 线程
g0 启动其他协程的
curg 现在正在运行的协程
mOS 记录针对不同操作系统的线程的一些信息

  1. 协程的执行

单线程循环
线程不断地去寻找协程调度

线程从 schedule()在g0 stack上执行,schedule() 在runtime 的proc
execute()在全局和本地队列去找 可用协程给gogo()使用
然后gogo()把goexit插入协程栈,执行业务方法,执行goexit(退出协程栈,进入g0栈)

没有进业务方法的时候用g0 stack 记录相关信息
执行业务方法时用g stack 记录函数变量等执行关系(协程g自带保护现场操作)
调度循环非常像线程池 ,(存在的问题:只能顺序执行)没有办法并发
多线程循环

GMP

p(队列) runtime2
m执行线程指针------头序号,尾序号,下一个执行协程的指针
本地没有,全局没有,就从其他的P偷一部分过来

协程饥饿问题
一些协程得不到执行,前端返回(服务端开小差了等等)
触发切换问题
一些协程运行超过一段时间,保存现场,将g stack信息放到g中加到队列后等待执行
本地队列的小循环?
隔着一段时间去全局队列找一些循环下,避免全局队列饥饿

mcall说明切换栈
主动挂起gopark() 休眠该协程,执行schedule
select,chan,sleep的等待都会走到gopark()
runtime调用这些gopark()

系统调用完成时
业务发生系统调用后,执行exitsyscall调用schedule()重新执行一个协程

主动挂起和系统调用防止饥饿
但是大协程一直在

runtime中的小写方法调用不了,是编译时给插进去的
业务函数跳转会用到morestack

两个shift找go文件,如果一个函数没有函数体,八成就是汇编了
ctrl + shift + f 全局搜索,在scope中查看

协程太多 panic
可能调度时间比运行时间还长
Go本身线程GMP已经池化,二级池化增加复杂度
Go语言初衷,协程即用击毁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值