登录
首页 >  Golang >  Go问答

锁定切片以进行读取和修改操作

来源:stackoverflow

时间:2024-02-08 14:55:03 239浏览 收藏

Golang小白一枚,正在不断学习积累知识,现将学习到的知识记录一下,也是将我的所得分享给大家!而今天这篇文章《锁定切片以进行读取和修改操作》带大家来了解一下##content_title##,希望对大家的知识积累有所帮助,从而弥补自己的不足,助力实战开发!


问题内容

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

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[i] = item

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

我已经实现了这个方法:

func getlist() *concurrentslice {
    if list == nil {
        denylist = newconcurrentslice()
        return denylist
    }
    return denylist
}

我这样使用它:

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

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

提前谢谢您!


正确答案


您执行阻止的方式不正确,因为它不能确保您退回的物品未被删除。如果进行更新,数组的长度至少仍相同。

一个更简单、有效的解决方案可能如下:

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)
    }
}

如果值的顺序不重要,请使用 sync.Map

type Items struct {
    m sync.Map
}

func (items *Items) Update(item Info) {
    items.m.Store(item.Name, item)
}

func (items *Items) Range(f func(Info) bool) {
    items.m.Range(func(key, value any) bool {
        return f(value.(Info))
    })
}

终于介绍完啦!小伙伴们,这篇关于《锁定切片以进行读取和修改操作》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布Golang相关知识,快来关注吧!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>