golang性能--defer

在golang编程中,我们很方便的使用defer来处理收尾工作。殊不知defer也是要消耗一部份性能作为代价的。那么defer到底对性能有多大影响,该怎么用就是值得考虑的问题了。

1. 性能的基准测试

基准测试入口函数,通过maxCount控制执行次数,deferFuncnormalFunc分别对应两种函数执行方式


//go:noinline
func doWork() {
	// 实际执行函数
}

func BenchmarkDefer(b *testing.B) {
	var maxCount = 1
	for count := 1; count <= maxCount; count++ {
		b.Run(strconv.Itoa(count), func(b *testing.B) {
			b.Run("defer", func(b *testing.B) {
				for i := 0; i < b.N; i++ {
					deferFunc(count)
				}
			})
			b.Run("normal", func(b *testing.B) {
				for i := 0; i < b.N; i++ {
					normalFunc(count)
				}
			})
		})
	}
}
  • 1.1 执行单个函数: 不使用任何控制流语句,直接执行
    BenchmarkDefer的maxCount=1
//go:noinline
func deferFunc(i int) () {
	defer doWork()
	return
}

//go:noinline
func normalFunc(i int) () {
	doWork()
	return
}


// BenchmarkDefer()

测试结果: 单个执行,defer相对normal慢3.32倍

BenchmarkDefer
BenchmarkDefer/1
BenchmarkDefer/1/defer
BenchmarkDefer/1/defer-8         	149949898	         7.987 ns/op
BenchmarkDefer/1/normal
BenchmarkDefer/1/normal-8        	538687286	         2.401 ns/op
  • 1.2 执行多个函数,使用控制流语句
    BenchmarkDefer的maxCount=4
//go:noinline
func deferFunc(i int) (out int) {
	switch i {
	case 1:
		defer doWork()
	case 2:
		defer doWork()
		defer doWork()
	case 3:
		defer doWork()
		defer doWork()
		defer doWork()
	case 4:
		defer doWork()
		defer doWork()
		defer doWork()
		defer doWork()
	}
	return
}

//go:noinline
func normalFunc(i int) (out int) {
	switch i {
	case 1:
		doWork()
	case 2:
		doWork()
		doWork()
	case 3:
		doWork()
		doWork()
		doWork()
	case 4:
		doWork()
		doWork()
		doWork()
		doWork()
	}
	return
}

// BenchmarkDefer()

测试结果:

BenchmarkDefer
BenchmarkDefer/1
BenchmarkDefer/1/defer
BenchmarkDefer/1/defer-8         	128937697	         9.280 ns/op
BenchmarkDefer/1/normal
BenchmarkDefer/1/normal-8        	337767033	         3.493 ns/op
BenchmarkDefer/2
BenchmarkDefer/2/defer
BenchmarkDefer/2/defer-8         	77090887	        15.49 ns/op
BenchmarkDefer/2/normal
BenchmarkDefer/2/normal-8        	270319077	         4.434 ns/op
BenchmarkDefer/3
BenchmarkDefer/3/defer
BenchmarkDefer/3/defer-8         	55449981	        21.67 ns/op
BenchmarkDefer/3/normal
BenchmarkDefer/3/normal-8        	251144298	         4.746 ns/op
BenchmarkDefer/4
BenchmarkDefer/4/defer
BenchmarkDefer/4/defer-8         	43583995	        27.61 ns/op
BenchmarkDefer/4/normal
BenchmarkDefer/4/normal-8        	211472344	         5.686 ns/op
执行次数defer / normal耗时比
12.65
23.49
34.56
44.85
  • 1.3 使用for循环执行指定次数
    BenchmarkDefer的maxCount=4
//go:noinline
func deferFunc(i int) (out int) {
	for ; i > 0; i-- {
		defer doWork()
	}
	return
}

//go:noinline
func normalFunc(i int) () {
	for ; i > 0; i-- {
		doWork()
	}
	return
}


// BenchmarkDefer()

测试结果:

BenchmarkDefer
BenchmarkDefer/1
BenchmarkDefer/1/defer
BenchmarkDefer/1/defer-8         	69172238	        17.40 ns/op
BenchmarkDefer/1/normal
BenchmarkDefer/1/normal-8        	250720538	         4.544 ns/op
BenchmarkDefer/2
BenchmarkDefer/2/defer
BenchmarkDefer/2/defer-8         	37119763	        32.14 ns/op
BenchmarkDefer/2/normal
BenchmarkDefer/2/normal-8        	182725000	         6.011 ns/op
BenchmarkDefer/3
BenchmarkDefer/3/defer
BenchmarkDefer/3/defer-8         	25962177	        46.19 ns/op
BenchmarkDefer/3/normal
BenchmarkDefer/3/normal-8        	158098609	         7.662 ns/op
BenchmarkDefer/4
BenchmarkDefer/4/defer
BenchmarkDefer/4/defer-8         	19954478	        61.62 ns/op
BenchmarkDefer/4/normal
BenchmarkDefer/4/normal-8        	130373722	         9.233 ns/op
执行次数defer / normal耗时比
13.83
25.34
36.02
46.67

2. 结论

  • 有多大影响
    • defer相对normal执行,是有性能损耗的,单次执行,defer/normal3.32
    • 执行次数越多,defer/normal耗时比越大;
    • 如果放在for循环中执行,则耗时比更大;
  • 使用建议
    • 避免在for循环中使用defer;
    • 对于执行频率较高的函数,避免使用defer;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值