gpt4 book ai didi

Go goroutine 加锁和解锁

转载 作者:IT王子 更新时间:2023-10-29 01:49:39 24 4
gpt4 key购买 nike

我一直在阅读有关 goroutines 和 sync 包的信息,我的问题是......在不同 goroutines 上读取写入数据时,我是否总是需要锁定解锁?

例如我的服务器上有一个变量

config := make(map[string]string)

然后在不同的 goroutines 上我想从配置中读取。不使用同步阅读是否安全?

我想写作需要使用同步包来完成。但我不确定是否阅读

例如我有一个简单的内存缓存系统

type Cache interface {
Get(key string) interface{}
Put(key string, expires int64, value interface{})
}

// MemoryCache represents a memory type of cache
type MemoryCache struct {
c map[string]*MemoryCacheValue
rw sync.RWMutex
}

// MemoryCacheValue represents a memory cache value
type MemoryCacheValue struct {
value interface{}
expires int64
}

// NewMemoryCache creates a new memory cache
func NewMemoryCache() Cache {
return &MemoryCache{
c: make(map[string]*MemoryCacheValue),
}
}

// Get stores something into the cache
func (m *MemoryCache) Get(key string) interface{} {
if v, ok := m.c[key]; ok {
return v
}
return nil
}

// Put retrieves something from the cache
func (m *MemoryCache) Put(key string, expires int64, value interface{}) {
m.rw.Lock()
m.c[key] = &MemoryCacheValue{
value,
time.Now().Unix() + expires,
}
m.rw.Unlock()
}

我在这里表现得很安全,或者当我只想阅读时我仍然需要锁定解锁?

最佳答案

您正在进入竞争条件的世界。基本的经验法则是,如果任何例程写入或更改一段数据,而该数据可以被任意数量的其他协程/线程读取或读取(或写入),您需要有某种同步系统。

例如,假设您有那张 map 。其中有 ["Joe"] = "Smith"和 ["Sean"] = "Howard"。一个 goroutine 想要读取 ["Joe"] 的值。另一个例程是将 ["Joe"] 更新为 "Cooper"。第一个 goroutine 读取哪个值?取决于哪个 goroutine 先获取数据。这就是竞争条件,行为是未定义且不可预测的。

控制该访问的最简单方法是使用 sync.Mutex。在您的情况下,由于某些例程只需要读取而不需要写入,因此您可以改用 sync.RWMutex (主要区别在于 RWMutex 允许任意数量的线程读,只要没有人试图写)。您可以使用如下结构将其烘焙到 map 中:

type MutexMap struct {
m map[string]string
*sync.RWMutex
}

然后,在需要从 map 中读取的例程中,您将执行:

func ReadSomething(o MutexMap, key string) string {
o.RLock() // lock for reading, blocks until the Mutex is ready
defer o.RUnlock() // make SURE you do this, else it will be locked permanently
return o.m[key]
}

然后写:

func WriteSomething(o MutexMap, key, value string) {
o.Lock() // lock for writing, blocks until the Mutex is ready
defer o.Unlock() // again, make SURE you do this, else it will be locked permanently
o.m[key] = value
}

请注意,如果需要,这两个都可以写成结构的方法,而不是函数。


您也可以使用 channel 来解决这个问题。您创建一个在 goroutine 中运行的 Controller 结构,并通过 channel 向它发出请求。示例:

package main

import "fmt"

type MapCtrl struct {
m map[string]string
ReadCh chan chan map[string]string
WriteCh chan map[string]string
QuitCh chan struct{}
}

func NewMapController() *MapCtrl {
return &MapCtrl{
m: make(map[string]string),
ReadCh: make(chan chan map[string]string),
WriteCh: make(chan map[string]string),
QuitCh: make(chan struct{}),
}
}

func (ctrl *MapCtrl) Control() {
for {
select {
case r := <-ctrl.ReadCh:
fmt.Println("Read request received")
retmap := make(map[string]string)
for k, v := range ctrl.m { // copy map, so it doesn't change in place after return
retmap[k] = v
}
r <- retmap
case w := <-ctrl.WriteCh:
fmt.Println("Write request received with", w)
for k, v := range w {
ctrl.m[k] = v
}
case <-ctrl.QuitCh:
fmt.Println("Quit request received")
return
}
}
}

func main() {
ctrl := NewMapController()
defer close(ctrl.QuitCh)
go ctrl.Control()

m := make(map[string]string)
m["Joe"] = "Smith"
m["Sean"] = "Howard"
ctrl.WriteCh <- m

r := make(chan map[string]string, 1)
ctrl.ReadCh <- r
fmt.Println(<-r)
}

Runnable version

关于Go goroutine 加锁和解锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38059618/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com