go - go map的内存高效实现?
问题描述
我的用例是通过网络传输一组成员(整数),因此我们采用增量编码,在接收端我们解码并将整个列表作为映射,map[string]struct{} 用于 O(1) 复杂度用于会员检查。
我面临的问题是,对于 200 万个整数,成员的实际大小仅为 15MB,但堆中映射的大小为 100+MB。似乎 Go 的实际地图实现不适合大型地图。由于它是客户端 SDK,我不想对可用内存造成太大影响,并且可能有多个这样的组需要长时间保存在内存中 - 大约 1 周。
在 Go 中有更好的替代 DS 吗?
type void struct{}
func ToMap(v []int64) map[string]void {
out := map[string]void{}
for _, i := range v {
out[strconv.Itoa(int(i))] = void{}
}
return out
}
解决方案
这是一种内存效率更高的映射形式:
type void struct{}
func ToMap(v []int64) map[int64]void {
m := make(map[int64]void, len(v))
for _, i := range v {
m[i] = void{}
}
return m
}
Go 地图针对整数键进行了优化。通过给出确切的地图大小作为提示来优化地图分配。
Astring
有一个隐式指针,这将使垃圾收集器 (gc) 每次扫描时都跟随指针。
这是 200 万个伪随机整数的 Go 基准测试:
package main
import (
"math/rand"
"strconv"
"testing"
)
type void struct{}
func ToMap1(v []int64) map[string]void {
out := map[string]void{}
for _, i := range v {
out[strconv.Itoa(int(i))] = void{}
}
return out
}
func ToMap2(v []int64) map[int64]void {
m := make(map[int64]void, len(v))
for _, i := range v {
m[i] = void{}
}
return m
}
var benchmarkV = func() []int64 {
v := make([]int64, 2000000)
for i := range v {
v[i] = rand.Int63()
}
return v
}()
func BenchmarkToMap1(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for N := 0; N < b.N; N++ {
ToMap1(benchmarkV)
}
}
func BenchmarkToMap2(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for N := 0; N < b.N; N++ {
ToMap2(benchmarkV)
}
}
输出:
$ go test tomap_test.go -bench=.
BenchmarkToMap1-4 2 973358894 ns/op 235475280 B/op 2076779 allocs/op
BenchmarkToMap2-4 10 188489170 ns/op 44852584 B/op 23 allocs/op
$
推荐阅读
- python - lib/pythonX.Y/no-global-site-packages.txt 的路径
- go - Go 包函数中的模拟函数
- android - 验证者 GSON 类型适配器
- r-markdown - bookdown 中不同引文包的问题
- amazon-web-services - 如何让现有用户成为 AWS Redshift 中的超级用户
- html - 当视口太长时,文本在跨度中重叠
- java - onResponse(String response) try { JSONObject jsonObject=new JSONObject(response);java.lang.String 无法转换为 JSONObject
- javascript - 在加载所有异步函数之前加载页面
- javascript - 将两个数组中的数据写入一个文档
- r - 文件上传后闪亮的 dplyr 过滤器不起作用