V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
reber0ask
V2EX  ›  Go 编程语言

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

  •  
  •   reber0ask ·
    reber0 · 2021-11-15 11:29:01 +08:00 · 2330 次点击
    这是一个创建于 1105 天前的主题,其中的信息可能已经有所发展或是发生改变。

    下面的代码,注释的地方,通过 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()
    }
    
    13 条回复    2021-11-19 17:36:35 +08:00
    k9982874
        1
    k9982874  
       2021-11-15 11:35:35 +08:00
    这代码嘈点太多。。自己再仔细自查一下
    reber0ask
        2
    reber0ask  
    OP
       2021-11-15 11:37:48 +08:00
    @k9982874 刚开始学 go ,,
    40EaE5uJO3Xt1VVa
        3
    40EaE5uJO3Xt1VVa  
       2021-11-15 11:39:33 +08:00
    @k9982874 求指点
    FakNoCNName
        4
    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
        5
    LemonK  
       2021-11-15 11:41:47 +08:00
    len(ch1) 会变小。
    clearT
        6
    clearT  
       2021-11-15 11:45:47 +08:00
    就是上面楼层说的问题,len(ch1) 是个动态的值,按照你那种写法也不一定只会丢一个,和 goroutine 的调度也有关系,所以运行结果是不确定的,丢几个都有可能
    reber0ask
        7
    reber0ask  
    OP
       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
        8
    reber0ask  
    OP
       2021-11-15 11:48:53 +08:00
    @LemonK @FakNoCNName @clearT 谢谢,明白了,确实是这样
    mmrindextt
        9
    mmrindextt  
       2021-11-15 13:41:22 +08:00
    for 中 go , 就值得细品了
    zjj19950716
        10
    zjj19950716  
       2021-11-15 16:16:11 +08:00
    @mmrindextt 展开讲讲
    snowlyg
        11
    snowlyg  
       2021-11-16 09:29:13 +08:00
    又看到这个问题,好想吐槽一下。哈哈
    wakaka
        12
    wakaka  
       2021-11-16 09:57:55 +08:00
    不得要领
    reber0ask
        13
    reber0ask  
    OP
       2021-11-19 17:36:35 +08:00
    @snowlyg 是我 sb 了。。len(ch1) 一直变
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2878 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 09:05 · PVG 17:05 · LAX 01:05 · JFK 04:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.