【defer】全新升级1.14以后的defer|Go主题月

简介: 在go1.14中,官方又对defer做了升级,据说这次升级把速度提升了一个量级。

网络异常,图片无法展示
|

1.14版本中的defer


go1.14中,官方又对defer做了升级,据说这次升级把速度提升了一个量级。

网络异常,图片无法展示
|

在编译期间,会直接把defer放到函数末尾去执行,省去了_defer结构体和链表的使用。官方把这种方法命名为:开放编码(Open Coded)

不过需要满足以下条件,否则并不会使用开放编码:

  • 函数的 defer 数量少于或者等于 8 个;
  • 函数的 defer 关键字不能在循环中执行;
  • 函数的 return 语句与 defer 语句的乘积小于或者等于 15 个;

延迟比特

为什么上面说defer的数量要小于等于8个呢?这是由于延迟比特的限制。延迟比特只有8个,默认值为0,每个对应一个defer,延迟比特的作用是判断defer语句到底要不要执行,例如:

package main
import "fmt"
func main() {
  i:=1
  if i==1{
    defer fmt.Println("defer")
  }
}

defer外面有一个if判断语句,当判断语句为true时,就会把对应的defer比特位设为1 。然后在函数末尾每个defer都会判断对应的比特位记录是否为1,如果为1就执行,否则就不执行。

网络异常,图片无法展示
|

使用时机

在当前版本中,defer一共有三种执行方式,那go到底是如何判断当前的defer是该用哪种方式呢?

代码生成阶段的 cmd/compile/internal/gc.state.stmt 会负责处理程序中的 defer,该函数会根据条件的不同,使用三种不同的机制处理该关键字:

func (s *state) stmt(n *Node) {
  ...
  switch n.Op {
  case ODEFER:
    if s.hasOpenDefers {
      s.openDeferRecord(n.Left) // 开放编码
    } else {
      d := callDefer // 堆分配
      if n.Esc == EscNever {
        d = callDeferStack // 栈分配
      }
      s.callResult(n.Left, d)
    }func (s *state) stmt(n *Node) {
  ...
  }
}

panic问题

虽然最新版本中的defer速度非常快,但是当程序发送panic时,在这之后的正常逻辑就都不会执行了,而是直接去执行defer链表。那些使用**开放地址(open coded)在函数内展开,因而没有被注册到链表的defer函数要通过栈扫描的方式来发现。所以1.14版本中就添加了几个字段用来辅助panic的栈扫描。

网络异常,图片无法展示
|

回顾

目录
打赏
0
0
0
0
3
分享
相关文章
|
11月前
|
Go
Go语言中defer的执行顺序详解
【2月更文挑战第22天】
143 4
全链路追踪 & 性能监控,GO 应用可观测全面升级
当前,大多数面向 Golang 应用的监控能力主要是通过 SDK 方式接入,需要开放人员手动进行埋点,会存在一定问题。对此,可观测 Go Agent 应运而生。本文介绍的阿里云可观测 Go Agent 方案,能通过无侵入的方式实现应用监控能力。
109084 34
|
8月前
|
Go
实验深度理解Go中try...catch...的panic、defer、recover用法
文章通过实验代码演示了Go语言中如何使用panic、defer和recover函数来模拟try...catch...的异常处理机制,并详细解释了每个函数的作用和在异常处理中的使用场景。
76 0
|
11月前
|
Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
Go语言中的`defer`、`panic`和`recover`提供了一套独特的异常处理方式。`defer`用于延迟函数调用,在返回前执行,常用于资源释放。它遵循后进先出原则。`panic`触发运行时错误,中断函数执行,直到遇到`recover`或程序结束。`recover`在`defer`中捕获`panic`,恢复程序执行。注意避免滥用`defer`影响性能,不应对可处理错误随意使用`panic`,且`recover`不能跨goroutine捕获panic。理解并恰当使用这些机制能提高代码健壮性和稳定性。
230 2
|
11月前
|
【Go语言专栏】Go语言中的延迟执行与defer语句
【4月更文挑战第30天】Go语言的延迟执行与defer语句用于资源释放和错误处理。defer通过关键字定义,函数返回时执行,顺序与定义相反。参数在定义时求值。应用包括资源释放、错误处理、成对操作和函数包装,是Go编程的关键特性。
80 0
|
11月前
|
Go-异常处理(defer recover panic)
Go-异常处理(defer recover panic)
94 0
go defer用法_类似与python_java_finially
go defer用法_类似与python_java_finially
100 0
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等