Golang Go语言中 goroutine 使用 chan 数据丢失的问题

发布于 1周前 作者 nodeper 来自 Go语言

Golang Go语言中 goroutine 使用 chan 数据丢失的问题

下面的代码,注释的地方,通过 for range 遍历时 go show1(x) 可以正常输出 1 到 10

但是使用 for 遍历时 go show2(x) 有时候不能完整的输出,只能输出 1 到 9 ,会丢失一部分

想问下是否我代码中 goroutine 使用的有问题,还是说只能通过 for range 给 goroutine 传值?

var (
	wg = sync.WaitGroup{}
)

func show1(x int) { defer wg.Done()

fmt.Println(x)

}

func show2(ch chan int) { defer wg.Done()

c := <-ch
fmt.Println(c)

}

func main() { ch1 := make(chan int, 40)

for i := 1; i < 11; i++ {
	ch1 <- i
}
close(ch1)

// for x := range ch1 {
// 	wg.Add(1)
// 	go show1(x)

// }

for j := 1; j < len(ch1)+1; j++ {
	wg.Add(1)
	go show2(ch1)
}

wg.Wait()

}


更多关于Golang Go语言中 goroutine 使用 chan 数据丢失的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

14 回复

这代码嘈点太多。。自己再仔细自查一下

更多关于Golang Go语言中 goroutine 使用 chan 数据丢失的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


刚开始学 go ,,

先考虑算法问题。

len(ch1)是个动态的值,你每次读取、写入数据都会变化。

按照你写的算法,最多输出 10~6 这几个数字,很好奇为什么只丢了一个?

改成下面的试试:
n := len(ch1)
for j := 0; j < n; j++ {
wg.Add(1)
go show2(ch1)
}

len(ch1) 会变小。

就是上面楼层说的问题,len(ch1) 是个动态的值,按照你那种写法也不一定只会丢一个,和 goroutine 的调度也有关系,所以运行结果是不确定的,丢几个都有可能

如果只向 chan 中传入了 1 到 10 的话可能丢失一个数字 10 ,如果传入 1 到 20 的话可能只能输出 1 到 17 、18 这样子, 按你的代码在 for 的外面使用 n := len(ch1)的话是没有问题的,确实可以输出 1 到 10 ,不会丢失数据

谢谢,明白了,确实是这样

for 中 go , 就值得细品了

又看到这个问题,好想吐槽一下。哈哈

是我 sb 了。。len(ch1) 一直变

在 Go 语言中,使用 goroutine 和 channel 时遇到数据丢失的问题,通常是由于并发编程中常见的竞态条件(race condition)或者 channel 使用不当导致的。以下是一些可能的原因和解决方案:

  1. 竞态条件:多个 goroutine 同时读写同一个 channel 而没有适当的同步机制,可能会导致数据丢失或程序崩溃。确保使用互斥锁(sync.Mutex)或原子操作(sync/atomic 包)来保护对共享资源的访问。

  2. channel 未正确关闭:如果生产者 goroutine 在消费者 goroutine 完成读取之前就关闭了 channel,那么未读取的数据将会丢失。确保在所有数据都被正确读取后再关闭 channel。

  3. 缓冲区溢出:对于带缓冲区的 channel,如果生产者发送数据的速度超过了消费者读取的速度,缓冲区可能会满,导致发送操作阻塞或数据丢失(如果使用了非阻塞发送)。可以通过增加缓冲区大小、优化生产者和消费者的速度或使用额外的同步机制来解决。

  4. goroutine 提前退出:如果某个 goroutine 在完成其任务之前意外退出,可能会导致它正在处理的数据丢失。确保所有 goroutine 都正确管理其生命周期。

解决这些问题通常需要仔细检查和调试代码,使用 Go 的 race detector(通过 go run -race)可以帮助识别竞态条件。此外,确保对并发编程的基本概念有深入的理解,是避免此类问题的关键。

回到顶部