本文介绍了并发读/写操作的 Golang 映射有多安全?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 Go 博客,

地图对于并发使用是不安全的:它没有定义当您同时读取和写入它们时会发生什么.如果您需要从并发执行的 goroutine 中读取和写入映射,则必须通过某种同步机制来调节访问.(来源:

添加:

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

检测比赛

更改读取功能:

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

另一个选择:

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

According to the Go blog,

Can anyone elaborate on this? Concurrent read operations seem permissible across routines, but concurrent read/write operations may generate a race condition if one attempts to read from and write to the same key.

Can this last risk be reduced in some cases? For example:

  • Function A generates k and sets m[k]=0. This is the only time A writes to map m. k is known to not be in m.
  • A passes k to function B running concurrently
  • A then reads m[k]. If m[k]==0, it waits, continuing only when m[k]!=0
  • B looks for k in the map. If it finds it, B sets m[k] to some positive integer. If it doesn't it waits until k is in m.

This isn't code (obviously) but I think it shows the outlines of a case where even if A and B both try to access m there won't be a race condition, or if there is it won't matter because of the additional constraints.

解决方案

Before Golang 1.6, concurrent read is OK, concurrent write is not OK, but write and concurrent read is OK. Since Golang 1.6, map cannot be read when it's being written.So After Golang 1.6, concurrent access map should be like:

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
}

Or you will get the error below:

ADDED:

You can detect the race by using go run -race race.go

Change the read function:

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

Another choise:

As we known, map was implemented by buckets and sync.RWMutex will lock all the buckets. concurrent-map use fnv32 to shard the key and every bucket use one sync.RWMutex.

这篇关于并发读/写操作的 Golang 映射有多安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-03 21:37