Golang关键字——defer

一、defer解决什么问题?

试想下,我们在一个函数中对临界区执行加锁操作,但是,临界区的代码可能会异常退出(如下图所示)。

为了防止这种情况,我们需要在每个err后面,都加上一个l.Unlock,这样的代码也难看了。为了解决这个问题,就需要这样的一个功能:能在函数、方法执行完毕后,进行一些收尾操作,这些操作可能是释放资源、或捕获panic错误,所以就有了defer这个关键字;

二、defer注意点

关于defer源码方面的信息,我觉得了解以下两点即可:

  • 知道defer函数会包装成一个_defer结构,挂载到相应的协程上;
  • 知道看汇编代码,找到defer的运行时函数runtime.deferreturn;

**【注】**没必要陷入看defer源码上实现上,了解以下这部分,就够了。如果开发过程中,有需求、有精力再去深究细节。

预参数计算

预参数计算,就是说再运行到defer函数的时候,它的参数就已经确定了。像下面这个例子打印出来的i为0

go 复制代码
func a() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}

Go Playground

LILO

go 复制代码
func b() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }
}

LILO,表示的是当运行到defer的时候,runtimedefer函数打包成一个_defer挂在到当前协程的_defer字段。对于上述代码,goroutine的图如下所示。当函数执行完时,从后到前执行对应链表,4,3,2,1

修改函数具名返回值

go 复制代码
func c() (i int) {
    defer func() { i++ }()
    return 1
}

上述代码,输出2。原因是,函数返回的1,先复制具名函数i,然后执行i++。「这部分有疑问,可以看下Golang函数布局」

三、defer性能损耗

defer带来方便的同时,也会带来一定的性能损耗。这个我们可以通过Benchmark来验证下。我们只需要了解有损耗即可,这点损耗对于大部分业务来说是没有影响的;

go 复制代码
func sum(max int) int {
   total := 0
   for i := 0; i < max; i++ {
      total += i
   }

   return total
}

func fooWithDefer() {
   defer func() {
      sum(10)
   }()
}

func fooWithOutDefer() {
   sum(10)
}

func BenchmarkFooWithDefer(b *testing.B) {
   for i := 0; i < b.N; i++ {
      fooWithDefer()
   }
}

func BenchmarkFooWithOutDefer(b *testing.B) {
   for i := 0; i < b.N; i++ {
      fooWithOutDefer()
   }
}
go 复制代码
➜  defer git:(master) ✗ go test -bench .                         
goos: darwin
goarch: amd64
pkg: go-tool/basic/defer
BenchmarkFooWithDefer-12        172309779                6.91 ns/op
BenchmarkFooWithOutDefer-12     249897656                4.76 ns/op
PASS
ok      go-tool/basic/defer     4.080s

总结

本文主要描述关于defer对的以下几点:

  1. defer解决什么问题?
  2. defer三个重要的特性,分别是预参数计算、LILO、修改函数具名返回值;
  3. 通过Benchmark了解defer带来的性能损耗;

参考

相关推荐
小咕聊编程32 分钟前
【含文档+源码】基于SpringBoot的过滤协同算法之网上服装商城设计与实现
java·spring boot·后端
追逐时光者7 小时前
推荐 12 款开源美观、简单易用的 WPF UI 控件库,让 WPF 应用界面焕然一新!
后端·.net
Jagger_7 小时前
敏捷开发流程-精简版
前端·后端
苏打水com8 小时前
数据库进阶实战:从性能优化到分布式架构的核心突破
数据库·后端
间彧9 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧9 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧9 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧9 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧9 小时前
Spring Cloud Gateway详解与应用实战
后端
EnCi Zheng10 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端