我们知道有两种初始化Map的方式(如下所示)。我想知道这两种方式之间是否存在性能差异。
var myMap map[string]int
那么
myMap = map[string]int{}
vs
myMap = make(map[string]int)
我们知道有两种初始化Map的方式(如下所示)。我想知道这两种方式之间是否存在性能差异。
var myMap map[string]int
那么
myMap = map[string]int{}
vs
myMap = make(map[string]int)
在我的机器上,它们看起来差不多。
您可以轻松进行基准测试以进行比较。例如:
package bench
import "testing"
var result map[string]int
func BenchmarkMakeLiteral(b *testing.B) {
var m map[string]int
for n := 0; n < b.N; n++ {
m = InitMapLiteral()
}
result = m
}
func BenchmarkMakeMake(b *testing.B) {
var m map[string]int
for n := 0; n < b.N; n++ {
m = InitMapMake()
}
result = m
}
func InitMapLiteral() map[string]int {
return map[string]int{}
}
func InitMapMake() map[string]int {
return make(map[string]int)
}
在三次不同的运行中,得出的结果非常接近,可以被视为无意义:
$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkMakeLiteral-8 10000000 160 ns/op
BenchmarkMakeMake-8 10000000 171 ns/op
ok github.com/johnweldon/bench 3.664s
$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkMakeLiteral-8 10000000 182 ns/op
BenchmarkMakeMake-8 10000000 173 ns/op
ok github.com/johnweldon/bench 3.945s
$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkMakeLiteral-8 10000000 170 ns/op
BenchmarkMakeMake-8 10000000 170 ns/op
ok github.com/johnweldon/bench 3.751s
分配空映射表时没有区别,但是使用make
命令,您可以传递第二个参数以预先分配映射表中的空间。这将节省在填充映射表时进行大量重新分配的时间。
package maps
import "testing"
const SIZE = 10000
func fill(m map[int]bool, size int) {
for i := 0; i < size; i++ {
m[i] = true
}
}
func BenchmarkEmpty(b *testing.B) {
for n := 0; n < b.N; n++ {
m := make(map[int]bool)
fill(m, SIZE)
}
}
func BenchmarkAllocated(b *testing.B) {
for n := 0; n < b.N; n++ {
m := make(map[int]bool, 2*SIZE)
fill(m, SIZE)
}
}
go test -benchmem -bench .
BenchmarkEmpty-8 500 2988680 ns/op 431848 B/op 625 allocs/op
BenchmarkAllocated-8 1000 1618251 ns/op 360949 B/op 11 allocs/op
make
比使用映射字面量更好。return map[string]float {
"key1": SOME_COMPUTED_ABOVE_VALUE,
"key2": SOME_COMPUTED_ABOVE_VALUE,
// more keys here
"keyN": SOME_COMPUTED_ABOVE_VALUE,
}
比...慢
// some code above
result := make(map[string]float, SIZE) // SIZE >= N
result["key1"] = SOME_COMPUTED_ABOVE_VALUE
result["key2"] = SOME_COMPUTED_ABOVE_VALUE
// more keys here
result["keyN"] = SOME_COMPUTED_ABOVE_VALUE
return result
对于很大的N(在我的用例中为N=300),这是一个问题。原因是编译器无法理解在第一种情况下至少需要分配N个插槽。
我写了一篇关于此的博客文章https://trams.github.io/golang-map-literal-performance/,并向社区报告了一个错误https://github.com/golang/go/issues/43020。
截至golang 1.17,这仍然是一个问题。