英文:
extra allocation when returning interface{} instead of int64
问题
我有一个生成随机int64
并将其作为interface{}
返回的函数,如下所示:
func Val1(rnd rand.Source) interface{} {
return rnd.Int63()
}
现在考虑这个函数,它做同样的事情,但返回一个int64
:
func Val2(rnd rand.Source) int64 {
return rnd.Int63()
}
我使用以下代码对这两个函数进行了基准测试(go test -bench=. -benchmem
):
func BenchmarkVal1(b *testing.B) {
var rnd = rand.NewSource(time.Now().UnixNano())
for n := 0; n < b.N; n++ {
Val1(rnd)
}
}
func BenchmarkVal2(b *testing.B) {
var rnd = rand.NewSource(time.Now().UnixNano())
for n := 0; n < b.N; n++ {
Val2(rnd)
}
}
测试结果如下:
BenchmarkVal1-4 50000000 32.4 ns/op 8 B/op 1 allocs/op
BenchmarkVal2-4 200000000 7.47 ns/op 0 B/op 0 allocs/op
Val1()
中的额外分配是从哪里来的?在返回interface{}
时能否避免这种情况?
英文:
I have a function that generates a random int64
and returns it as an interface{}
like this:
func Val1(rnd rand.Source) interface{} {
return rnd.Int63()
}
now consider this function, which does the same thing but returns a int64
func Val2(rnd rand.Source) int64 {
return rnd.Int63()
}
I benchmarked the two functions with this (go test -bench=. -benchmem
) :
func BenchmarkVal1(b *testing.B) {
var rnd = rand.NewSource(time.Now().UnixNano())
for n := 0; n < b.N; n++ {
Val1(rnd)
}
}
func BenchmarkVal2(b *testing.B) {
var rnd = rand.NewSource(time.Now().UnixNano())
for n := 0; n < b.N; n++ {
Val2(rnd)
}
}
and got folowing results:
BenchmarkVal1-4 50000000 32.4 ns/op 8 B/op 1 allocs/op
BenchmarkVal2-4 200000000 7.47 ns/op 0 B/op 0 allocs/op
Where does the extra allocation in Val1()
come from ? Can it be avoided when returning an interface{}
?
答案1
得分: 5
一个接口值是一个包装器,它包含了具体值和类型描述符的一对。
阅读这篇文章以获取更多信息:反射定律 #接口的表示
所以,如果你想返回一个interface{}
类型的值,将会隐式地创建一个interface{}
值(如果返回的值尚未是该类型),它将保存整数和类型描述符,表示int64
类型。你无法避免这一点。
interface{}
是一个特殊的接口类型(没有方法)。正如你在基准输出中看到的那样,它的值只有8个字节。其他接口类型的大小更大(两倍),因为它们还必须标识接口类型的静态方法集(除了动态类型和值)。
还请确保查看这个有信息量的答案:https://stackoverflow.com/questions/23148812/go-whats-the-meaning-of-interface/23148998#23148998
如果你想了解更多关于实现/内部的信息,我推荐阅读这篇文章:Golang中接口的工作原理
英文:
An interface value is a wrapper under the hood, a pair of the concrete value stored in the interface value and its type descriptor.
Read this for more information: The Laws of Reflection #The representation of an interface
So if you want to return a value of interface{}
type, an interface{}
value will be implicitly created (if the value being returned is not already of that type), which will hold the integer number and its type descriptor denoting the int64
type. You can't avoid this.
interface{}
is a special interface type (having 0 methods). Its value is only 8 bytes as you see on the benchmark output. Other interface types have larger size (double) as they also have to identify the static method set of the interface type (besides the dynamic type and value).
Also be sure to check out this informative answer: https://stackoverflow.com/questions/23148812/go-whats-the-meaning-of-interface/23148998#23148998
If you want more information about the implementation / internals, I recommend this post: How Interfaces Work in Golang
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论