简体   繁体   English

为什么迭代地图比在Golang中迭代切片要慢得多?

[英]Why is iterating over a map so much slower than iterating over a slice in Golang?

I was implementing a sparse matrix using a map in Golang and I noticed that my code started taking much longer to complete after this change, after dismissing other possible causes, seems that the culprit is the iteration on the map itself. 我在Golang中使用地图实现了一个稀疏矩阵,我注意到我的代码在这个改变之后开始花了很长时间才完成,在消除了其他可能的原因后,似乎罪魁祸首就是地图本身的迭代。 Go Playground link (doesn't work for some reason). Go Playground链接 (由于某种原因不起作用)。

package main

import (
    "fmt"
    "time"
    "math"
)

func main() {
    z := 50000000
    a := make(map[int]int, z)
    b := make([]int, z)

    for i := 0; i < z; i++ {
        a[i] = i
        b[i] = i
    }

    t0 := time.Now()
    for key, value := range a {
        if key != value { // never happens
            fmt.Println("a", key, value)
        }
    }
    d0 := time.Now().Sub(t0)

    t1 := time.Now()
    for key, value := range b {
        if key != value { // never happens
            fmt.Println("b", key, value)
        }
    }
    d1 := time.Now().Sub(t1)

    fmt.Println(
        "a:", d0,
        "b:", d1,
        "diff:", math.Max(float64(d0), float64(d1)) / math.Min(float64(d0), float64(d1)),
    )
}

Iterating over 50M items returns the following timings: 迭代超过50M的项目将返回以下时间:

alix@local:~/Go/src$ go version
go version go1.3.3 linux/amd64
alix@local:~/Go/src$ go run b.go 
a: 1.195424429s b: 68.588488ms diff: 17.777154632611037

I wonder, why is iterating over a map almost 20x as slow when compared to a slice? 我想知道,与切片相比,为什么在地图上迭代的速度几乎是20倍?

This comes down to the representation in memory. 这归结为记忆中的表现。 How familiar are you with the representation of different data structures and the concept of algorithmic complexity? 您对不同数据结构的表示和算法复杂性的概念有多熟悉? Iterating over an array or slice is simple. 迭代数组或切片很简单。 Values are contiguous in memory. 值在内存中是连续的。 However iterating over a map requires traversing the key space and doing lookups into the hash-table structure. 但是,迭代映射需要遍历密钥空间并对哈希表结构进行查找。

The dynamic ability of maps to insert keys of any value without using up tons of space allocating a sparse array, and the fact that look-ups can be done efficiently over the key space despite being not as fast as an array, are why hash tables are sometimes preferred over an array, although arrays (and slices) have a faster "constant" (O(1)) lookup time given an index. 映射插入任意值的键而不占用大量空间来分配稀疏数组的动态能力,以及尽管没有数组那么快就可以在密钥空间上高效完成查找的事实,这就是散列表的原因虽然数组(和切片)在给定索引时具有更快的“常量” (O(1))查找时间,但有时优先于数组。

It all comes down to whether you need the features of this or that data structure and whether you're willing to deal with the side-effects or gotchas involved. 这一切都取决于您是否需要这个或那个数据结构的功能,以及您是否愿意处理所涉及的副作用或陷阱。

Seems reasonable to put my comment as an answer. 将我的评论作为答案似乎是合理的。 The underlying structures who's iteration performance you're comparing are a hash table and an array ( https://en.wikipedia.org/wiki/Hash_table vs https://en.wikipedia.org/wiki/Array_data_structure ). 您正在比较的迭代性能的基础结构是哈希表和数组( https://en.wikipedia.org/wiki/Hash_table vs https://en.wikipedia.org/wiki/Array_data_structure )。 The range abstraction is actually (speculation, can't find the code) iterating all the keys, accessing each value, and assigning the two to k,v := . 范围抽象实际上是(猜测,找不到代码)迭代所有密钥,访问每个值,并将两者分配给k,v := If you're not familiar with accessing in the array it is constant time because you just add sizeof(type)*i to the starting pointer to get the item. 如果你不熟悉在数组中访问它是恒定的时间,因为你只需将sizeof(type)* i添加到起始指针以获取项目。 I don't know what the internals of map are in golang but I know enough to know that it's memory representation and therefor access is nothing close that efficient. 我不知道golang的内部是什么,但我知道它是内存表示,因此访问并不是那么有效。

The specs statement on the topic isn't much; 关于这个主题的规范声明并不多; http://golang.org/ref/spec#For_statements http://golang.org/ref/spec#For_statements

If I find the time to look up the implementation of range for map and slice/array I will and put some more technical details. 如果我找到时间来查找map和slice / array的范围实现,我会提出更多技术细节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM