go - 使用 channel 发送到多个 slice 时数据丢失

标签 go concurrency

我最近在学习 golang 的并发性,我在想一个程序生成一系列数字,然后将它们同时发送到三个 slice 。这是代码:

func main() {
    ch := make(chan int)
    done := make(chan bool)
    var bag1 []int
    var bag2 []int
    var bag3 []int

    go func() {
        for i := 0; i < 1000000; i++ {
            ch <- i
        }
        close(ch)
        done <- true
    }()

    go sendToBag(&bag1, ch)
    go sendToBag(&bag2, ch)
    go sendToBag(&bag3, ch)

    <-done

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

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

输出如下:

length of bag1: 327643
length of bag2: 335630
length of bag3: 336725
total length: 999998

三个 slice 的总长度并不总是加起来等于发送给它们的数字计数。所以我的问题是:是什么导致了问题以及如何改进代码

最佳答案

您对 done 的使用 channel 根本不足以保证所有 3 sendToBag goroutines 完全完成他们的工作。

虽然 channel 确实被 for n := range ch {“完全耗尽”了声明之前 <-done被执行时,您的代码中没有任何内容可以确保 <-done在最后的 *bag = append(*bag, n) 之后 执行被执行,因此不能保证 len()对包的调用将仅在 append() 之后执行电话。

使用 WaitGroup 而不是完成 channel 。

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

    go func() {
        for i := 0; i < 1000000; i++ {
            ch <- i
        }
        close(ch)
    }()

    wg.Add(3)
    go sendToBag(&bag1, ch, &wg)
    go sendToBag(&bag2, ch, &wg)
    go sendToBag(&bag3, ch, &wg)

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

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

https://go.dev/play/p/_wDgS5aS7bI

关于go - 使用 channel 发送到多个 slice 时数据丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71284340/

相关文章:

java - 禁用后对 jButton 执行的操作

java - 使用 Wea​​kReference 的并发缓存会引发 NPE

unit-testing - 如何在golang中测试 sleep 功能

go - 键变量在 Stripe Go SDK 中被覆盖

GoCQL : Marshal string into timestamp

java - 如何在可运行的 Runnable 内部隐藏 JavaFX 组件?

MySQL:面对大量并发的正确性(SELECT ... FOR UPDATE)

java - 如何刷新到 Java 的 JTextArea?

time - 从时间戳中获取一年的第一天和最后一天

go - io.copyN 不是第一次调用时不能工作