go - 并发读/写操作的 Golang 映射有多安全?

标签 go concurrency hashmap

根据 Go 博客,

Maps are not safe for concurrent use: it's not defined what happens when you read and write to them simultaneously. If you need to read from and write to a map from concurrently executing goroutines, the accesses must be mediated by some kind of synchronization mechanism. (source: https://blog.golang.org/go-maps-in-action)

谁能详细说明一下?跨例程的并发读取操作似乎是允许的,但如果尝试读取和写入同一个键,则并发读取/写入操作可能会产生竞争条件。

在某些情况下可以降低最后一个风险吗?例如:

  • 函数 A 生成 k 并设置 m[k]=0。这是 A 唯一一次写入映射 m。已知 k 不在 m 中。
  • A 将 k 传递给同时运行的函数 B
  • A 然后读取 m[k]。如果 m[k]==0,它会等待,仅当 m[k]!=0 时才继续
  • B 在 map 中寻找 k。如果找到它,B 将 m[k] 设置为某个正整数。如果不是,它会等到 k 在 m 中。

这不是代码(显然),但我认为它显示了即使 A 和 B 都尝试访问 m 也不会出现竞争条件的情况的轮廓,或者如果存在则无关紧要因为额外的限制。

最佳答案

在Golang 1.6之前,并发读是可以的,并发写是不行的,但是写并发读是可以的。从 Golang 1.6 开始,map 在写入时无法读取。 所以在Golang 1.6之后,并发访问图应该是这样的:

package main

import (
    "sync"
    "time"
)

var m = map[string]int{"a": 1}
var lock = sync.RWMutex{}

func main() {
    go Read()
    time.Sleep(1 * time.Second)
    go Write()
    time.Sleep(1 * time.Minute)
}

func Read() {
    for {
        read()
    }
}

func Write() {
    for {
        write()
    }
}

func read() {
    lock.RLock()
    defer lock.RUnlock()
    _ = m["a"]
}

func write() {
    lock.Lock()
    defer lock.Unlock()
    m["b"] = 2
}

否则您将收到以下错误: enter image description here

添加:

您可以使用 go run -race race.go

检测比赛

更改读取功能:

func read() {
    // lock.RLock()
    // defer lock.RUnlock()
    _ = m["a"]
}

enter image description here

另一个选择:

众所周知,map 是由桶实现的,sync.RWMutex 会锁定所有桶。 concurrent-map使用 fnv32 对 key 进行分片,每个桶使用一个 sync.RWMutex

关于go - 并发读/写操作的 Golang 映射有多安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36167200/

相关文章:

string - 规范包 : how do I combine separate characters?

amazon-web-services - 使用 AWS Go 开发工具包的动态 list

java - 无法从 Runnable.run 方法更新 swing 组件

java - 为什么下面的程序中 HashMap 类的 containsValue 方法返回 False?

unit-testing - 错误 : suite. go:61: test paniced: reflect: Call with too few input arguments

c++ - Go 和 C++ 中的 vector 性能

java - 多线程安全类

concurrency - 如何减少 CUDA 同步延迟/延迟

java - Java HashMap 中的 Varargs

java - 比较 Hashmap 和 List list = new Arraylist()