Golang Go语言中 goroutine 使用 chan 数据丢失的问题
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
这代码嘈点太多。。自己再仔细自查一下
更多关于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 使用不当导致的。以下是一些可能的原因和解决方案:
-
竞态条件:多个 goroutine 同时读写同一个 channel 而没有适当的同步机制,可能会导致数据丢失或程序崩溃。确保使用互斥锁(sync.Mutex)或原子操作(sync/atomic 包)来保护对共享资源的访问。
-
channel 未正确关闭:如果生产者 goroutine 在消费者 goroutine 完成读取之前就关闭了 channel,那么未读取的数据将会丢失。确保在所有数据都被正确读取后再关闭 channel。
-
缓冲区溢出:对于带缓冲区的 channel,如果生产者发送数据的速度超过了消费者读取的速度,缓冲区可能会满,导致发送操作阻塞或数据丢失(如果使用了非阻塞发送)。可以通过增加缓冲区大小、优化生产者和消费者的速度或使用额外的同步机制来解决。
-
goroutine 提前退出:如果某个 goroutine 在完成其任务之前意外退出,可能会导致它正在处理的数据丢失。确保所有 goroutine 都正确管理其生命周期。
解决这些问题通常需要仔细检查和调试代码,使用 Go 的 race detector(通过 go run -race
)可以帮助识别竞态条件。此外,确保对并发编程的基本概念有深入的理解,是避免此类问题的关键。