Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do Go implementations store the length of a map?

Tags:

dictionary

go

Does a map have its length stored somewhere or is it calculated each time we call len(my_map)?

The language spec shows this for maps, which doesn't really help:

The number of map elements is called its length. For a map m, it can be discovered using the built-in function len and may change during execution. Elements may be added during execution using assignments and retrieved with index expressions; they may be removed with the delete built-in function.

Under the "Length and capacity" section we see this:

The expression len(s) is constant if s is a string constant. The expressions len(s) and cap(s) are constants if the type of s is an array or pointer to an array and the expression s does not contain channel receives or (non-constant) function calls; in this case s is not evaluated. Otherwise, invocations of len and cap are not constant and s is evaluated.

So it tells us that s isn't constant and is evaluated but it doesn't state if it's looked up as a stored value like they do with the slice type.

like image 519
Lye Fish Avatar asked Aug 01 '15 04:08

Lye Fish


People also ask

How do you get the size of a map in Go?

To get length of map in Go programming, call len() function and pass map as argument to it. The function returns an integer representing the number of key:value pairs in the map.

How is a map stored in a Golang?

In Go language, a map is a powerful, ingenious, and versatile data structure. Golang Maps is a collection of unordered pairs of key-value. It is widely used because it provides fast lookups and values that can retrieve, update or delete with the help of keys. It is a reference to a hash table.

How much memory does a Golang map use?

A map of type map[string]int with an initial capacity of 100 now requires 4176 bytes (on 64-bit arch). The default initial capacity is around 7 if not specified explicitly.

Is Golang map a hash map?

It uses a hashing function on the key to generate an index into an array of data.


Video Answer


1 Answers

I haven't checked the sources, but I wrote a quick benchmark.

It tests 4 maps, 2 where keys are int, 2 where keys are string.

var m1 = make(map[int]int)    // key is of type int, len(m1) = 10
var m2 = make(map[int]int)    // key is of type int, len(m2) = 1000000
var s1 = make(map[string]int) // key is of type string, len(s1) = 10
var s2 = make(map[string]int) // key is of type string, len(s2) = 1000000

"Small" maps have 10 elements, "large" maps have a million elements. Maps are populated like this:

func init() {
    for i := 0; i < 10; i++ {
        m1[i] = i
        s1[strconv.Itoa(i)] = i
    }
    for i := 0; i < 1000000; i++ {
        m2[i] = i
        s2[strconv.Itoa(i)] = i
    }
}

A benchmark function looks like this:

func BenchmarkSmallIntMap(b *testing.B) {
    for i := 0; i < b.N; i++ {
        for j := 0; j < 1000; j++ {
            _ = len(m1) + len(m1) + len(m1) + len(m1) + len(m1) + len(m1)
        }
    }
}

All the others are similar, but using m2, s1 and s2 obviously. Here are the results:

BenchmarkSmallIntMap     1000000              2085 ns/op
BenchmarkLargeIntMap     1000000              2087 ns/op
BenchmarkSmallStringMap  1000000              2087 ns/op
BenchmarkLargeStringMap  1000000              2086 ns/op

All are the same which pretty much tells that execution time of len(m) does not depend on the map size (number of key-value pairs), which suggests that map length is stored and not "counted" when called.

If interested, here is the complete test source: Go Playground.

And twotwotwo checked the sources, the length is stored.

like image 102
icza Avatar answered Oct 20 '22 09:10

icza