Go语言 为并发访问锁定Map的Map

nwwlzxa7  于 2023-09-28  发布在  Go
关注(0)|答案(1)|浏览(86)

我有一张Map:map[string]map[string]* 我需要在多个Go例程中读/写的结构。
实现这一目标的最佳途径是什么?Mutex还是RWMutex?放在哪里
如果我使用RWMutex,那么我应该在做一个涉及读和写的操作之前锁定还是锁定?
我试着在根Map中有一个rwmutex,但我不确定这是否是解决这个问题的最佳方法。
另外,我试图“锁定”之前读和写,但我收到“并发写”恐慌有时。

6pp0gazn

6pp0gazn1#

您可以使用RWLock。如果操作涉及到写(不管是读还是写),你需要使用锁,如果只有读,那么使用RLock/RUnlock。
锁也可以被认为是排他性的锁。另一方面,RLock是非排他性的。即使RWMutex已经被锁定阅读,也可以获取RLock,但是如果资源被Lock方法独占锁定,则会阻止goroutine执行:

a blocked Lock call excludes new readers from acquiring the lock

另一方面,Lock方法阻止goroutine执行,直到所有的读写器解锁资源(使用RUnlock/Unlock方法)。Lock是独占的,因为只有一个goroutine可以访问资源(无论是阅读还是写),直到Unlock方法被调用。
典型方法:

package main

import (
    "fmt"
    "sync"
)

type SomeStruct struct {
    someInfo string
}

type ConcurrentStruct struct {
    mu   sync.RWMutex
    data map[string]map[string]*SomeStruct
}

func New() *ConcurrentStruct {
    return &ConcurrentStruct{
        data: make(map[string]map[string]*SomeStruct),
    }
}

func (cs *ConcurrentStruct) Set(key1, key2 string, val SomeStruct) {
    cs.mu.Lock()
    defer cs.mu.Unlock()

    if _, ok := cs.data[key1]; !ok {
        cs.data[key1] = make(map[string]*SomeStruct)
    }
    cs.data[key1][key2] = &val
}

func (cs *ConcurrentStruct) Get(key1, key2 string) (val *SomeStruct, ok bool) {
    cs.mu.RLock()
    defer cs.mu.RUnlock()

    if _, ok := cs.data[key1]; ok {
        val, ok := cs.data[key1][key2]
        return val, ok
    }

    return nil, false
}

func main() {
    cs := New()
    cs.Set("a", "b", SomeStruct{"Hello, World!"})

    if _, ok := cs.Get("a", "c"); !ok {
        fmt.Printf("key1=a, key2=c, not found\n")
    }

    if s, ok := cs.Get("a", "b"); ok {
        fmt.Printf("key1=a, key2=b, found: %v\n", s)
    }
}

相关问题