Golang中如何避免channel丢失最后一个元素

Golang中如何避免channel丢失最后一个元素 大家好

我这里有段示例代码。在我正在开发的一个更大项目中,也遇到了类似的情况。

https://play.golang.org/p/eiFA6yuvpOa

有人能向我解释为什么最后一个数字丢失了吗?当我执行代码时,数字9不见了。我不明白为什么会发生这种情况。

谢谢

3 回复

看起来我完全做错了 😊

我注意到了我的错误,以下是解决方案:

https://play.golang.org/p/4gDVCC3uZtM

package main

import (
    "fmt"
)

func main() {
    numbers := make(chan int)
    
    go func() {
        for i := 0; i < 100; i++ {
            numbers <- i
        }
        close(numbers)
    }()

    for n := range numbers {
        fmt.Println(n)
    }
}

更多关于Golang中如何避免channel丢失最后一个元素的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


main() 函数结束时,整个程序就会停止,即使正在运行的 goroutine 尚未完成。 添加如下等待逻辑:

https://goinbigdata.com/golang-wait-for-all-goroutines-to-finish/

你所有关于并发的问题,答案都在这本极好的书中:

Go 并发编程 作者:Katherine Cox-Buday 出版时间:2017年8月 出版社:O’Reilly Media, Inc. ISBN:9781491941294

不要犹豫。直接买下这本书,然后阅读它。你会庆幸自己这么做了。

祝你好运。

这是因为主 goroutine 在消费者 goroutine 处理完所有元素之前就提前退出了。当 range 循环读取完 channel 中的最后一个元素后,主 goroutine 立即执行 wg.Done() 并结束,而此时消费者可能还在处理最后一个元素。

以下是修复后的代码:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	ch := make(chan int)

	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 0; i < 10; i++ {
			ch <- i
		}
		close(ch) // 关闭channel
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for v := range ch { // range会自动检测channel关闭
			fmt.Println(v)
		}
	}()

	wg.Wait() // 等待两个goroutine都完成
}

关键修改:

  1. 生产者 goroutine 在发送完所有数据后关闭 channel
  2. 消费者 goroutine 使用 for v := range ch 来读取,这会一直读取直到 channel 被关闭
  3. 使用 sync.WaitGroup 确保两个 goroutine 都完成后再退出主程序

这样就能确保所有元素都被处理,输出结果为 0 到 9 的所有数字。

回到顶部