检查在存储大值的映射中是否存在键。

huangapple go评论67阅读模式
英文:

Check if key exists in map storing large values

问题

在Go语言中,要判断一个键k是否存在于映射M1[k]v中非常简单。

if v, ok := M1[k]; ok {
    // 键存在
}

'v': 非指针类型的值。

如果v很大,仅仅使用上述方法检查特定键是否存在并不高效,因为它会将值v加载到内存中(即使我在v的位置使用空白标识符_,根据我的理解,请纠正我如果我理解错了)。

是否有一种高效的方法可以检查映射中是否存在某个键(而不需要读取或分配值到内存中)?

我在考虑创建一个新的映射M2[k]bool来存储信息,并在每次向M1插入内容时在M2中进行记录。

英文:

To know a key k exist in a map M1[k]v is very straightforward in Go.

if v, ok := M1[k]; ok {
    // key exist
}

'v': a value of a non-pointer type.

If v is large, To just check if a particular key exists using the above method is not efficient as it will load the value v in the memory(even if I use a blank identifier _ in the place of v as per my understanding and please correct me if my understanding is wrong here).

Is there an efficient way in which we can check if a key is present in a Map(without reading/or the value is allocated in the memory)?

I am thinking to create a new map M2[k]bool to store the information and make an entry in M2 each time I insert something in M1.

答案1

得分: 7

使用if _, ok := M1[k]; ok { }。如果使用空白标识符,值将不会被"加载"。

让我们编写基准测试来测试它:

var m = map[int][1_000_000]int64{
    1: {},
}

func BenchmarkNonBlank(b *testing.B) {
    for i := 0; i < b.N; i++ {
        if v, ok := m[1]; ok {
            if false {
                _ = v
            }
        }
    }
}

func BenchmarkBlank(b *testing.B) {
    for i := 0; i < b.N; i++ {
        if _, ok := m[1]; ok {
            if false {
                _ = ok
            }
        }
    }
}

运行go test -bench .,输出结果为:

BenchmarkNonBlank-8         1497            763278 ns/op
BenchmarkBlank-8        97802791                12.09 ns/op

如你所见,使用空白标识符,操作大约需要10纳秒。当我们将值分配给非空白标识符时,它几乎需要1毫秒(大约慢了十万倍),当值类型的大小约为8 MB时。

英文:

Use if _, ok := M1[k]; ok { }. If you use the blank identifier, the value will not be "loaded".

Let's write benchmarks to test it:

var m = map[int][1_000_000]int64{
	1: {},
}

func BenchmarkNonBlank(b *testing.B) {
	for i := 0; i &lt; b.N; i++ {
		if v, ok := m[1]; ok {
			if false {
				_ = v
			}
		}
	}
}

func BenchmarkBlank(b *testing.B) {
	for i := 0; i &lt; b.N; i++ {
		if _, ok := m[1]; ok {
			if false {
				_ = ok
			}
		}
	}
}

Running go test -bench ., the output is:

BenchmarkNonBlank-8         1497            763278 ns/op
BenchmarkBlank-8        97802791                12.09 ns/op

As you can see, using the blank identifier, the operation takes about 10 ns. When we assign the value to a non-blank identifier, it's almost 1 ms (almost a hundred thousand times slower) when the value type has a size of around 8 MB.

huangapple
  • 本文由 发表于 2022年1月3日 00:53:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/70557883.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定