出于好奇,我写了一些简单的基准测试,将golang地图的性能与用作地图的JavaScript(v8 / node.js)对象进行比较,并对其相对性能感到惊讶。 JavaScript对象的执行速度大约是go map的两倍(甚至包括go的一些小的性能边缘)!
以下是go实现:
// map.go
package main
import "fmt"
import "time"
func elapsedMillis(t0, t1 time.Time) float64 {
n0, n1 := float64(t0.UnixNano()), float64(t1.UnixNano())
return (n1 - n0) / 1e6
}
func main() {
m := make(map[int]int, 1000000)
t0 := time.Now()
for i := 0; i < 1000000; i++ {
m[i] = i // Put.
_ = m[i] + 1 // Get, use, discard.
}
t1 := time.Now()
fmt.Printf("go: %fms\n", elapsedMillis(t0, t1))
}
这是JavaScript:
#!/usr/bin/env node
// map.js
function elapsedMillis(hrtime0, hrtime1) {
var n0 = hrtime0[0] * 1e9 + hrtime0[1];
var n1 = hrtime1[0] * 1e9 + hrtime1[1];
return (n1 - n0) / 1e6;
}
var m = {};
var t0 = process.hrtime();
for (var i=0; i<1000000; i++) {
m[i] = i; // Put.
var _ = m[i] + 1; // Get, use, discard.
}
var t1 = process.hrtime();
console.log('js: ' + elapsedMillis(t0, t1) + 'ms');
请注意,go实现具有以下几个潜在的性能优势:
Go直接将整数映射到整数,而JavaScript会将整数键转换为字符串属性名称。
Go使其地图的初始容量等于基准尺寸,而JavaScript则从其默认容量增长。
然而,尽管上面列出了潜在的性能优势,但是go map使用似乎只能执行JavaScript对象映射的一半!例如(代表):
go: 128.318976ms
js: 48.18517ms
我是否在做地图或以某种方式将苹果与橙子进行比较时做了明显错误的事情?
我原本期望go map至少也能执行 - 如果不比JavaScript对象好,那就像map一样。这只是go的不成熟的标志(darwin / amd64上的1.4)还是它代表了我缺少的两种语言数据结构之间的一些根本区别?
[更新]
请注意,如果您明确使用字符串键(例如分别通过Go和JavaScript中的s := strconv.Itoa(i)
和var s = ''+i
),那么它们的效果大致相当。
我的猜测是,v8的高性能与该运行时针对其连续整数的对象的特定优化有关(例如,通过替换数组实现而不是哈希表)。
我投票结束,因为这里可能没有什么可看的......
答案 0 :(得分:5)
您的基准测试有点合成,就像任何基准测试一样。只是为了好奇的尝试
for i := 0; i < 1000000; i += 9 {
在Go实现中。你可能会感到惊讶。