映射delete()实际上并不删除条目

时间:2019-10-20 16:57:10

标签: go

在地图中进行多次添加/删除后,在地图上的测距速度比预期的慢。

考虑以下代码

package main

import (
    "fmt"
    "time"
)

func main() {
    test := make(map[int]bool)
    for i := 0; i < 1000000; i++ {
        test[i] = true
    }
    for k := range test {
        delete(test, k)
    }
    test[0] = true
    fmt.Printf("test len(): %d\n", len(test))
    now := time.Now()
    for range test {
    }
    fmt.Printf("range took %v\n", time.Since(now))
}

在我的系统上,循环测试映射(包含1个条目)需要3.5毫秒。这是一个问题,因为我们在生产环境中运行类似的代码,并且一段时间后,每个映射都有数百万个已删除的条目。

GC似乎无济于事,我能想到的唯一解决方案是将整个地图设置为nil,然后重新制作它。还有其他方法吗?

1 个答案:

答案 0 :(得分:2)

我希望性能会根据地图的最大尺寸大致缩放,但是我不希望随着时间的推移进行更多的写入和删除操作,性能会变得更糟。有两个部分;是时候检查所有存储桶了,这将根据地图的大小进行缩放,并且产生结果的时间将根据当前存在的条目数进行缩放。

但是添加和删除内容不应进一步更改它。

https://play.golang.org/p/Ouj-3MuZvVt

另请参阅https://github.com/golang/go/issues/20135,该问题跟踪“地图在删除后不会缩小”。

如果您确实需要遍历地图的一小部分,则可能需要制作一个仅包含您要保留的项目的新地图,但这并不是花费您时间的插入/删除操作,它是地图已经请注意,如果您添加和删除1000个项目(而不是添加一百万个项目然后删除它们),则时间消耗要小得多。