Go 语言不支持并发读写 Map,为什么?

开发 前端
在Go语言的设计中,为了防止数据竞态,不同于一些其他语言,map并没有提供内置的锁机制。这样设计的目的是为了鼓励开发者使用更加精细的同步措施,以适应不同的并发场景。

Go语言的map类型不支持并发读写的主要原因是并发读写会导致数据竞态(data race),这意味着多个 goroutine 可能同时访问并修改同一个 map,从而引发不确定的结果。

在Go语言的设计中,为了防止数据竞态,不同于一些其他语言,map并没有提供内置的锁机制。这样设计的目的是为了鼓励开发者使用更加精细的同步措施,以适应不同的并发场景。

如果你需要在多个 goroutine 中安全地使用 map,可以考虑以下几种方法:

1 加锁: 使用 sync.Mutex 或 sync.RWMutex 来保护对 map 的读写操作。

package main

import (
    "sync"
)

var (
    mu   sync.Mutex
    data = make(map[string]string)
)

func writeToMap(key, value string) {
    mu.Lock()
    defer mu.Unlock()
    data[key] = value
}

func readFromMap(key string) string {
    mu.Lock()
    defer mu.Unlock()
    return data[key]
}

func main() {
    // 使用 writeToMap 和 readFromMap 安全地对 map 进行读写
}

2 使用 sync.Map: 在Go 1.9及以上版本,标准库中提供了 sync.Map 类型,它是一种并发安全的 map 实现。

package main

import (
    "sync"
)

var m sync.Map

func main() {
    // 使用 m.Store() 和 m.Load() 安全地对 map 进行读写
}

sync.Map 提供了一些方法来实现并发安全的读写操作,而无需额外的锁。

图片图片

3 使用通道: 可以通过通道在不同的 goroutine 之间传递消息,避免直接对 map 进行并发访问。

package main

import (
    "sync"
)

var (
    data     = make(map[string]string)
    readCh   = make(chan readRequest)
    writeCh  = make(chan writeRequest)
    shutdown = make(chan struct{})
    wg       sync.WaitGroup
)

type readRequest struct {
    key    string
    result chan<- string
}

type writeRequest struct {
    key, value string
}

func startDispatcher() {
    for {
        select {
        case req := <-readCh:
            req.result <- data[req.key]
        case req := <-writeCh:
            data[req.key] = req.value
        case <-shutdown:
            return
        }
    }
}

func writeToMap(key, value string) {
    writeCh <- writeRequest{key, value}
}

func readFromMap(key string) string {
    resultCh := make(chan string)
    readCh <- readRequest{key, resultCh}
    return <-resultCh
}

func main() {
    go startDispatcher()

    // 使用 writeToMap 和 readFromMap 安全地对 map 进行读写

    // 关闭通道和等待后台 goroutine 完成
    close(shutdown)
    wg.Wait()
}

这些方法中,具体选择取决于应用场景和需求。使用锁可能会引入一些开销,而 sync.Map 或基于通道的方法可能更适用于某些情况。

责任编辑:武晓燕 来源: Go语言圈
相关推荐

2024-01-01 08:10:40

Go语言map

2021-10-27 07:15:36

Go 循环引用

2022-01-10 23:54:56

GoMap并发

2021-12-15 07:49:22

Go语言设计

2021-12-09 10:51:47

Go继承

2024-03-12 09:13:28

Go语言main

2023-01-28 08:05:32

转换Go泛型

2021-11-08 11:02:01

Go函数重载

2023-02-26 23:36:08

PHPGo函数

2024-03-08 08:51:59

Gomain函数

2020-10-09 06:48:19

Pythonswitch语句

2020-07-22 08:01:41

Python开发运算符

2021-02-01 13:53:53

StringlongJava

2009-03-12 08:42:38

AndroidWMMTK

2021-06-11 00:03:31

鸿蒙智能手机

2021-08-02 09:31:20

Python工具代码

2021-07-13 08:09:34

微博推特评论

2023-04-03 11:21:29

PythonGoRust

2009-03-11 17:32:22

联发科WMAndroid

2019-04-25 15:20:23

KafkaJava编程语言
点赞
收藏

51CTO技术栈公众号