【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的栈扫描。

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

回顾

相关文章
|
1天前
|
Go
Go语言中defer的执行顺序详解
【2月更文挑战第22天】
29 4
|
6月前
|
Cloud Native Go
GO 中的 defer 有哪些注意事项?上
GO 中的 defer 有哪些注意事项?上
|
1天前
|
Java Go 区块链
【Go语言专栏】Go语言中的延迟执行与defer语句
【4月更文挑战第30天】Go语言的延迟执行与defer语句用于资源释放和错误处理。defer通过关键字定义,函数返回时执行,顺序与定义相反。参数在定义时求值。应用包括资源释放、错误处理、成对操作和函数包装,是Go编程的关键特性。
|
1天前
|
Go 开发者
Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
Go语言中的`defer`、`panic`和`recover`提供了一套独特的异常处理方式。`defer`用于延迟函数调用,在返回前执行,常用于资源释放。它遵循后进先出原则。`panic`触发运行时错误,中断函数执行,直到遇到`recover`或程序结束。`recover`在`defer`中捕获`panic`,恢复程序执行。注意避免滥用`defer`影响性能,不应对可处理错误随意使用`panic`,且`recover`不能跨goroutine捕获panic。理解并恰当使用这些机制能提高代码健壮性和稳定性。
26 2
|
5月前
|
Dubbo 应用服务中间件 API
Go语言微服务框架重磅升级:dubbo-go v3.2.0 -alpha 版本预览
随着 Dubbo3 在云原生微服务方向的快速发展,Dubbo 的 go 语言实现迎来了 Dubbo3 版本以来最全面、最大幅度的一次升级,这次升级是全方位的,涉及 API、协议、流量管控、可观测能力等。
|
1天前
|
网络协议 BI Go
Go-异常处理(defer recover panic)
Go-异常处理(defer recover panic)
32 0
|
5月前
|
Go
go defer用法_类似与python_java_finially
go defer用法_类似与python_java_finially
38 0
|
6月前
|
Cloud Native Go C++
GO 中的 defer 有哪些注意事项?下
GO 中的 defer 有哪些注意事项?下
golang 之 defer(统计函数执行时间)
1 package main 2 3 import ( 4 "fmt" 5 "time" 6 ) 7 8 func sum(a ...int) int { 9 defer trace("sum")() // note:不要忘记defe...
1354 0
|
1天前
|
安全 测试技术 数据库连接
使用Go语言进行并发编程
【5月更文挑战第15天】Go语言以其简洁语法和强大的并发原语(goroutines、channels)成为并发编程的理想选择。Goroutines是轻量级线程,由Go运行时管理。Channels作为goroutine间的通信机制,确保安全的数据交换。在编写并发程序时,应遵循如通过通信共享内存、使用`sync`包同步、避免全局变量等最佳实践。理解并发与并行的区别,有效管理goroutine生命周期,并编写测试用例以确保代码的正确性,都是成功进行Go语言并发编程的关键。

热门文章

最新文章