当返回interface{}而不是int64时,会有额外的分配。

huangapple go评论167阅读模式
英文:

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 &lt; b.N; n++ {
		Val1(rnd)
	}
}

func BenchmarkVal2(b *testing.B) {
	var rnd = rand.NewSource(time.Now().UnixNano())
	for n := 0; n &lt; 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

huangapple
  • 本文由 发表于 2017年7月27日 19:56:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/45350097.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定