在我的计算机上,当我访问特定大小的 map 时,我看到每秒读取量下降,但它不会以线性方式降低。事实上,性能会立即下降,然后随着大小的增加缓慢恢复:
$ go run map.go 425984 1 425985
273578 wps :: 18488800 rps
227909 wps :: 1790311 rps
$ go run map.go 400000 10000 500000
271355 wps :: 18060069 rps
254804 wps :: 18404288 rps
267067 wps :: 18673778 rps
216442 wps :: 1984859 rps
246724 wps :: 2461281 rps
282316 wps :: 3634125 rps
216615 wps :: 4989007 rps
276769 wps :: 6972233 rps
212019 wps :: 9756720 rps
286027 wps :: 14488593 rps
227073 wps :: 17309822 rps
我预计写入偶尔会变慢(因为调整了底层数据结构的大小),但读取对大小敏感(并且是一个数量级)让我感到惊讶。
这是我用来测试的代码:
package main
import (
"bytes"
"fmt"
"math/rand"
"os"
"strconv"
"time"
)
func main() {
start, _ := strconv.ParseInt(os.Args[1], 10, 64)
step, _ := strconv.ParseInt(os.Args[2], 10, 64)
end, _ := strconv.ParseInt(os.Args[3], 10, 64)
for n := start; n <= end; n += step {
runNTimes(n)
}
}
func randomString() string {
var b bytes.Buffer
for i := 0; i < 16; i++ {
b.WriteByte(byte(0x61 + rand.Intn(26)))
}
return b.String()
}
func perSecond(end time.Time, start time.Time, n int64) float64 {
return float64(n) / end.Sub(start).Seconds()
}
func runNTimes(n int64) {
m := make(map[string]int64)
startAdd := time.Now()
for i := int64(0); i < n; i++ {
m[randomString()]++
}
endAdd := time.Now()
totalInMap := int64(0)
startRead := time.Now()
for _, v := range m {
//get around unused variable error,
//v should always be > 0
if v != 0 {
totalInMap++
}
}
endRead := time.Now()
fmt.Printf("%10.0f wps :: %10.0f rps\n",
perSecond(endAdd, startAdd, n),
perSecond(endRead, startRead, totalInMap),
)
}
最佳答案
您的代码本身不衡量 map 性能。您的代码测量执行随机数生成(不保证是恒定时间操作)、测距 map (不保证是恒定时间操作并且不保证以与普通 map 访问性能相关的任何可预测方式)和也许它甚至可以测量干扰“停止世界”垃圾收集。
- 不要编写自己的工作台功能,使用什么package "testing"优惠,就好多了。例如,它从不依赖样本大小 == 1(就像您的代码错误地那样)。
- 此外,在测量时间之外生成所有测试 key 。
- 然后,为了尽量减少 GC 影响,perform runtime.GC() .
- 现在终于可以使用了
B.StartTimer
并执行测量的代码路径。
无论如何,无论您要正确测量什么,都不会太有用。 map 代码是 Go 运行时的一个实现细节,可以随时更改。据我所知,当前的实现与 Go 1 中的完全不同。
最后:是的,调整良好的 map 实现可能对许多事情敏感,包括其中项目的数量和/或大小和/或类型 - 甚至架构和 CPU 步进和缓存大小也可以发挥作用在这方面的作用。
关于performance - 为什么我在使用范围时看到某些尺寸的 map 速度变慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17909822/