golang type assertion and unsafe.Pointer 性能对比
程序员文章站
2022-06-22 21:05:50
...
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{}的拆箱,装箱,以及类型断言的实际原理有关。
上一篇: 推动网站内容营销的三大目标与注意事项
下一篇: php session劫持和防范的方法