golang type assertion and unsafe.Pointer 性能对比

Posted 惜暮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang type assertion and unsafe.Pointer 性能对比相关的知识,希望对你有一定的参考价值。

golang type assertion and unsafe.Pointer 性能对比

最近项目中有这样一个需求背景:有一个存储实体用来做各种指标的counter。这个counter的实现需要能够在以后被别的实现替换。结构自然是这样:

type XXXObj struct 
	startTime uint64
	counter interface//暂时用interface表示,表示该对象类似于泛型的存在

为了避免对象拷贝,所以其实这里存储的一定会是一个指针。所以这里还有一个可选方案:unsafe.Pointer.

最初的设计,这一块更像泛型的一种思想,所以很自然的使用了interface。

但是上层拿到这个 interface 之后肯定要做类型断言,转成实际的counter对象指针,然后执行实际的统计操作。这一块是一个非常高频的调用。所以performance是非常重要的点。

所以想测试一下:直接调用、类型断言,unsafe.Pointer转换三种方式的性能对比。下面是一个test 的benchmark。这里申明一下这里仅仅针对泛型对象是指针的场景:

package assertion

import (
	"testing"
	"unsafe"
)

type Student struct 
	Name  string
	Age   int
	Class string
	Score int



func DirectInvoke(s *Student) 
	s.Name = "Jerry"
	s.Age = 18
	s.Class = "20005"
	s.Score = 100


func PointerInvoke(p unsafe.Pointer)  
	s := (*Student)(p)
	s.Name = "Jerry"
	s.Age = 18
	s.Class = "20005"
	s.Score = 100

func InterfaceInvoke(i interface) 
	s := i.(*Student)
	s.Name = "Jerry"
	s.Age = 18
	s.Class = "20005"
	s.Score = 100


func BenchmarkAssertDirectInvoke(b *testing.B) 
	s := new(Student)
	b.ResetTimer()
	for i := 0; i < b.N; i++ 
		DirectInvoke(s)
	
	_ = s


func BenchmarkAssertPointerInvoke(b *testing.B) 
	s := new(Student)
	b.ResetTimer()
	for i := 0; i < b.N; i++ 
		PointerInvoke(unsafe.Pointer(s))
	
	_ = s


func BenchmarkAssertInterfaceInvoke(b *testing.B) 
	s := new(Student)
	b.ResetTimer()
	for i := 0; i < b.N; i++ 
		InterfaceInvoke(s)
	
	_ = s

三种场景跑出来的结果是:

// 环境:mac pro 2015, 13-in, 4核8G内存

$go test -bench='BenchmarkAssert*' -benchmem
goos: darwin
goarch: amd64
pkg: study_golang/study/basic/assertion
BenchmarkAssertDirectInvoke-4           1000000000               0.328 ns/op           0 B/op          0 allocs/op
BenchmarkAssertPointerInvoke-4          1000000000               0.332 ns/op           0 B/op          0 allocs/op
BenchmarkAssertInterfaceInvoke-4        559252803                2.03 ns/op            0 B/op          0 allocs/op
PASS
ok      study_golang/study/basic/assertion      2.095s

从benchmark结果来看,直接调用和使用指针的性能基本是一样的。但是使用interface再做 type assertion 的方式就性能相比就差很多了。但是实际指令执行的速度都是在ns 级别,所以速度似乎又都能接受。

我们应该关注的应该是,为什么 interface 的方式和type assertion速度会差这么多?根据我的了解,这里应该与 interface的拆箱,装箱,以及类型断言的实际原理有关。

以上是关于golang type assertion and unsafe.Pointer 性能对比的主要内容,如果未能解决你的问题,请参考以下文章