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 性能对比的主要内容,如果未能解决你的问题,请参考以下文章

Golang type assertion 类型断言

Golang type assertion 类型断言

Golang type assertion 类型断言

golang --Converting and Checking Types

Symfony @Assert\Type("string") 验证通过整数值

keycloak 中的“参数 client_assertion_type 丢失”