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

Go语言并发场景下使用Channel向多个Slice发送数据时的数据丢失问题排查与优化方案

问题分析与解决方案

嘿,这个问题我之前写Go并发程序的时候也踩过一模一样的坑,咱们先唠唠为啥总长度会不对,再看看怎么改代码能解决问题。

问题成因

你的代码核心问题出在等待时机不对:

  • 生产者goroutine发送完1000000个数字后,会执行close(ch)然后给done通道发信号。
  • 主goroutine一收到done信号就立刻统计slice长度,但这时候三个消费者goroutine很可能还没处理完通道里剩下的元素。因为通道被关闭后,消费者的for n := range ch循环会继续读取通道内剩余的所有元素,直到通道彻底为空才会退出循环。主goroutine提前结束,导致统计时有些元素还没被append到slice里,总长度自然就小于预期了。

补充一句:你的代码里每个消费者操作的是各自独立的slice,所以不存在多个goroutine同时修改同一个slice的竞态问题,这部分是没问题的。

优化方案

最简洁靠谱的做法是用sync.WaitGroup来等待所有消费者goroutine完全处理完所有数据,再进行统计。修改后的代码如下:

import (
    "fmt"
    "sync"
)

func main() {
    ch := make(chan int)
    var wg sync.WaitGroup
    var bag1 []int
    var bag2 []int
    var bag3 []int

    // 生产者goroutine:负责生成数据并发送到通道
    go func() {
        for i := 0; i < 1000000; i++ {
            ch <- i
        }
        close(ch) // 关闭通道,告知消费者不再有新数据
    }()

    // 启动三个消费者,同时注册到WaitGroup
    wg.Add(3)
    go func() {
        defer wg.Done() // 确保goroutine退出时通知WaitGroup
        sendToBag(&bag1, ch)
    }()
    go func() {
        defer wg.Done()
        sendToBag(&bag2, ch)
    }()
    go func() {
        defer wg.Done()
        sendToBag(&bag3, ch)
    }()

    wg.Wait() // 阻塞等待所有消费者完成任务

    len1 := len(bag1)
    len2 := len(bag2)
    len3 := len(bag3)
    fmt.Println("length of bag1:", len1)
    fmt.Println("length of bag2:", len2)
    fmt.Println("length of bag3:", len3)
    fmt.Println("total length:", len1+len2+len3) // 现在总数一定会是1000000
}

func sendToBag(bag *[]int, ch <-chan int) {
    for n := range ch {
        *bag = append(*bag, n)
    }
}

优化点说明

  • 用sync.WaitGroup替代原有的done通道:wg.Add(3)标记需要等待3个goroutine,每个消费者goroutine用defer wg.Done()确保无论函数如何退出,都会通知WaitGroup任务完成。
  • 主goroutine调用wg.Wait()会一直阻塞,直到所有消费者都处理完通道内的所有数据(消费者循环会读到通道为空才退出),这时候再统计长度就完全准确了。
  • 生产者只需要专注于生成数据和关闭通道,逻辑更清晰,不需要额外处理done信号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 14:17:44