go - 在读取和修改之前锁定 slice

标签 go concurrency slice

我最近使用 Go 的经验,在审查一些代码时,我发现虽然它被写保护,但读取数据时存在问题。不是读取本身,而是读取和修改 slice 之间可能发生的修改。

type ConcurrentSlice struct {
    sync.RWMutex
    items []Item
}

type Item struct {
    Index int
    Value Info
}

type Info struct {
    Name        string 
    Labels      map[string]string
    Failure     bool

}

如前所述,写作以这种方式受到保护:


func (cs *ConcurrentSlice) UpdateOrAppend(item ScalingInfo) {
    found := false
    i := 0
    for inList := range cs.Iter() {
        if item.Name == inList.Value.Name{
            cs.items[i] = item
            found = true
        }
        i++
    }
    if !found {
        cs.Lock()
        defer cs.Unlock()

        cs.items = append(cs.items, item)
    }
}

func (cs *ConcurrentSlice) Iter() <-chan ConcurrentSliceItem {
    c := make(chan ConcurrentSliceItem)

    f := func() {
        cs.Lock()
        defer cs.Unlock()
        for index, value := range cs.items {
            c <- ConcurrentSliceItem{index, value}
        }
        close(c)
    }
    go f()

    return c
}

但是在收集 slice 的内容和修改它之间,可能会发生修改。可能是另一个例程修改了同一个 slice ,当该赋值时,它已经不存在了:slice[i ] = 项目

处理这个问题的正确方法是什么?

我已经实现了这个方法:

func GetList() *ConcurrentSlice {
    if list == nil {
        denylist = NewConcurrentSlice()
        return denylist
    }
    return denylist
}

我是这样使用它的:

concurrentSlice := GetList()
concurrentSlice.UpdateOrAppend(item)

但我知道在获取和修改之间,即使它实际上是立即的,另一个例程也可能修改了 slice 。以原子方式执行这两个操作的正确方法是什么?我阅读的 slice 100% 是我修改的 slice 。因为如果我尝试将一个项目分配给一个不再存在的索引,它会中断执行。

提前致谢!

最佳答案

您进行阻止的方式是不正确的,因为它不能确保您退回的元素没有被移除。在更新的情况下,数组仍将至少保持相同的长度。

一个更简单的可行解决方案如下:

func (cs *ConcurrentSlice) UpdateOrAppend(item ScalingInfo) {
    found := false
    i := 0
    cs.Lock()
    defer cs.Unlock()

    for _, it := range cs.items {
        if item.Name == it.Name{
            cs.items[i] = it
            found = true
        }
        i++
    }
    if !found {
        cs.items = append(cs.items, item)
    }
}

关于go - 在读取和修改之前锁定 slice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73859360/

相关文章:

python - 仅在选定区域中查找 2d-Numpy 数组中最大值的索引

python - numpy 中 3D 数组的 2D 切片系列

go - Monorepo : How to consume a package from another project?

go - 使用 git2go 添加和提交新文件

python - 1 个带有 Gunicorn 的 Web Worker 是否总是意味着只有 1 个进程?

dictionary - 使用附加属性作为键从结构创建映射或对象

go - 为什么这个延迟语句(没有返回)运行时没有返回值?

go - 等待 gin HTTP 服务器启动

java - 我如何包装一个方法,以便在它超过指定超时时终止它的执行?

java - 为什么在 Java 内存模型中允许这种行为?