Go语言 模块中根变量的竞态条件?

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

在模块中使用“根”变量时,是否可能遇到竞态条件?
假设您有一个名为db的模块,并且在编译项目中导入了许多不同的文件

package db

var global_var map[string]string

你能确定这个变量对于许多并发的读写是持久的吗?在一个文件中,db.global_var被更改,然后新值被分发到导入了db包的所有其他文件中。
如何实现具有原子功能的解决方案?

ecfdbz9o

ecfdbz9o1#

如果你想同时使用map进行读/写,你必须使用一些同步。在其他情况下,它将导致竞争条件。最简单的实现方法-使用sync.Mutex或sync.RWMutex(在并发读/写的情况下更有效)。
您也可以使用sync.map作为替代。但它可以更慢,因为它的通用性质。map使用interface{}(或任何只是interface{}的别名)作为map的键和值。因此,您需要Assert类型(type assertion不是非常快的操作)。
典型方法:

package main

import (
    "fmt"
    "sync"
)

type SyncMap struct {
    mu sync.RWMutex
    m  map[string]string
}

func New() *SyncMap {
    return &SyncMap{
        m: make(map[string]string),
    }
}

func (sm *SyncMap) Set(key, val string) {
    sm.mu.Lock()
    defer sm.mu.Unlock() // or without defer in the end of method - will be faster
    sm.m[key] = val
}

func (sm *SyncMap) Get(key string) (val string, ok bool) {
    sm.mu.RLock()
    defer sm.mu.RUnlock() // or without defer in the end of method - will be faster
    val, ok = sm.m[key]
    return
}

func (sm *SyncMap) Delete(key string) {
    delete(sm.m, key)
}

func main() {
    m := New()

    key := "Hello"
    val := ", World!"

    v, ok := m.Get(key)
    fmt.Printf("%s %s OK: %v\n", key, v, ok)

    m.Set(key, val)
    v, ok = m.Get(key)
    fmt.Printf("%s %s OK: %v\n", key, v, ok)

    m.Delete(key)
    v, ok = m.Get(key)
    fmt.Printf("%s %s OK: %v\n", key, v, ok)
}

但是如果你想在变化的情况下分配变量值,我认为,最好使用基于通道的方法。

相关问题