golang 中 goroutine 使用 chan 数据丢失的问题

2021-11-15 11:29:01 +08:00
 reber0ask

下面的代码,注释的地方,通过 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()
}
2184 次点击
所在节点    Go 编程语言
13 条回复
k9982874
2021-11-15 11:35:35 +08:00
这代码嘈点太多。。自己再仔细自查一下
reber0ask
2021-11-15 11:37:48 +08:00
@k9982874 刚开始学 go ,,
yanzhiling2001
2021-11-15 11:39:33 +08:00
@k9982874 求指点
FakNoCNName
2021-11-15 11:41:42 +08:00
先考虑算法问题。

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

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

改成下面的试试:
n := len(ch1)
for j := 0; j < n; j++ {
wg.Add(1)
go show2(ch1)
}
LemonK
2021-11-15 11:41:47 +08:00
len(ch1) 会变小。
clearT
2021-11-15 11:45:47 +08:00
就是上面楼层说的问题,len(ch1) 是个动态的值,按照你那种写法也不一定只会丢一个,和 goroutine 的调度也有关系,所以运行结果是不确定的,丢几个都有可能
reber0ask
2021-11-15 11:47:30 +08:00
@LemonK 如果只向 chan 中传入了 1 到 10 的话可能丢失一个数字 10 ,如果传入 1 到 20 的话可能只能输出 1 到 17 、18 这样子, 按你的代码在 for 的外面使用 n := len(ch1)的话是没有问题的,确实可以输出 1 到 10 ,不会丢失数据
reber0ask
2021-11-15 11:48:53 +08:00
@LemonK @FakNoCNName @clearT 谢谢,明白了,确实是这样
mmrindextt
2021-11-15 13:41:22 +08:00
for 中 go , 就值得细品了
zjj19950716
2021-11-15 16:16:11 +08:00
@mmrindextt 展开讲讲
snowlyg
2021-11-16 09:29:13 +08:00
又看到这个问题,好想吐槽一下。哈哈
wakaka
2021-11-16 09:57:55 +08:00
不得要领
reber0ask
2021-11-19 17:36:35 +08:00
@snowlyg 是我 sb 了。。len(ch1) 一直变

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/815458

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX