go语言中的GMP、defer、匿名defer函数、defer执行流程
题目来源:奇安信
答案1:
defer 意为延迟,在golang中用于延迟执行一个函数,主要用于帮助我们处理资源释放、连接关闭等一些操作
若函数中有多个defer,其执行顺序为先进后出,可以理解为栈
在理解匿名defer函数之前,首先得了解一个知识点:
go的函数返回值是通过堆栈返回的,return语句不是原子操作,而是被拆成了下面两步
给返回值赋值(rval)
返回给调用函数(ret)
defer是在return之前执行的。这个在官方文档中是明确说明了的。要使用defer时不踩坑,最重要的一点就是要明白,return xxx这一条语句并不是一条原子指令!
函数返回的过程是这样的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。
defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。
其实使用defer时,用一个简单的转换规则改写一下,就不会迷糊了。改写规则是将return语句拆成两句写,return xxx会被改写成:
返回值 = xxx
调用defer函数
空的return
GMP执行流程,调度模型
新创建的Goroutine会先存放在Global全局队列中,等待Go调度器进行调度,随后Goroutine被分配给其中的一个逻辑处理器P,并放到这个逻辑处理器对应的Local本地运行队列中,最终等待被逻辑处理器P执行即可。
在M与P绑定后,M会不断从P的Local队列中无锁地取出G,并切换到G的堆栈执行,当P的Local队列中没有G时,再从Global队列中获取一个G,当Global队列中也没有待运行的G时,则尝试从其它的P窃取部分G来执行相当于P之间的负载均衡。