You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Goroutine安全更新Slice?Go并发编程问题求助

Go并发更新Slice的问题与解决方法

初始错误实现

我在尝试从并行Goroutine中更新Slice时遇到了问题,最初写出了这段明知不正确的代码:

func main() {

    var dwpList = []int {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    var mmrpList []int
    
    var wg sync.WaitGroup

    ch1 := make(chan int)

    cores := 4

    wg.Add(cores + 1)

    for i := 0; i < cores; i++ {
        go func1(&mmrpList, ch1, &wg)
    }

    iterateSamples(dwpList, ch1, &wg)

    close(ch1)

    wg.Wait()

    fmt.Println(mmrpList)

}

func iterateSamples(dwpList []int, ch1 chan<- int, wg *sync.WaitGroup) {

    defer wg.Done()

    for _, dwp := range dwpList {
    
        ch1 <- dwp
    }
}

func func1(mmrpList *[]int, ch1 <-chan int, wg *sync.WaitGroup) {

    defer wg.Done()

    for dwp := range ch1 {
    
        *mmrpList = append(*mmrpList, dwp)
    }
}

显然这段代码无法正常工作,因为多个Goroutine同时向Slice执行append操作——Slice的底层数组是共享资源,并发append会引发数据竞争、底层数组扩容时的状态不一致等问题,最终结果完全不可预测。

当我尝试将append操作移至由额外通道、WaitGroup等控制的独立函数时,总会遇到编译错误或死锁问题(有时是WaitGroup的Wait/Done调用逻辑出错),或者程序退化为单线程执行,完全失去并发意义。

修正后的实现

调整代码结构后,我写出了如下版本,终于成功实现了需求:

func main() {

    var dwpList = []int {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    var mmrpList []int
    
    var wg sync.WaitGroup

    ch1 := make(chan int)
    ch2 := make(chan int)

    cores := 4

    wg.Add(1)
    go func() {
        defer wg.Done()
        // Get data
        for _, dwp := range dwpList {
            ch1 <- dwp
        }
        close(ch1)
    }()

    for i := 0; i < cores; i++ {

        wg.Add(1)
        go func() {
            defer wg.Done()
            // Do stuff then pass data on
            for dwp := range ch1 {
                ch2 <- dwp
            }
        }()
    }

    go func() {
        wg.Wait()
        close(ch2)
    }()

    for dwp := range ch2 {
        mmrpList = append(mmrpList, dwp)
    }

    fmt.Println(mmrpList)

}

这个版本的核心改进点:

  • 让ch1的写入操作在单个Goroutine中执行,避免数据竞争
  • 用第二个通道ch2统一接收所有工作Goroutine的处理结果,仅在主线程中执行append操作,彻底规避了并发修改Slice的风险
  • 通过独立Goroutine等待所有工作Goroutine完成后再关闭ch2,确保主线程能完整遍历所有结果

内容的提问来源于stack exchange,提问作者shakeshuck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 10:12:43