doufeiqiong3515 2017-04-02 09:28
浏览 641
已采纳

带有sync.WaitGroup的Goroutines在最后wg.Done()之前结束

I have an example code (you can find it on Go Playground):

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    messages := make(chan int)
    var wg sync.WaitGroup
    var result []int

    // you can also add these one at 
    // a time if you need to 

    wg.Add(1)
    go func() {
        defer wg.Done()
        time.Sleep(time.Second * 1)
        messages <- 1
    }()
    wg.Add(1)
    go func() {
        defer wg.Done()
        time.Sleep(time.Second * 1)
        messages <- 2
    }() 
    wg.Add(1)
    go func() {
        defer wg.Done()
        time.Sleep(time.Second * 1)
        messages <- 3
    }()
    go func() {
        for i := range messages {
            fmt.Println(i)
        result = append(result, i)
        }

    }()

    wg.Wait()
    fmt.Println(result)
}

I got this output:

2
1
[2 1]

I think I know why is it happening, but I can't solve it. There is 3 item in the WaitGroup I mean the three goroutine, and the 4th groutine consume the data from the channel. When the last groutine say wg.Done() the program is over because of the wg.Wait() said every goroutine finished and the last goroutine result the 4th goroutine couldn't have consume, because the program ended. I tryed to add plus one with wg.Add(1) and the wg.Done() in the 4th function but in this case I got deadlock.

  • 写回答

3条回答 默认 最新

  • doom910730 2017-04-02 09:34
    关注

    The last goroutine you spawn—that one intended to collect the results—is not waited by main() so wg.Wait() in there returns, main() quits and reaps the remainin goroutines. Supposedly just a single—collecting—goroutine remains by that time but it fails to update the slice.

    Also note that due to the same reason you have a data race in your program: by the time main() reads the slice of results, it does not know whether it's safe to read it—that is, whether the writer is done writing to there.

    An easy fix is to do add wg.Add(1) for that goroutine and defer wg.Done() in it, too.

    A better solution is to close() the messages channel after wg.Wait() and before reading from the slice. This would make the collecting goroutine's range loop to terminate and this would also create a proper synchronization point between that goroutine and main().

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥50 mac mini外接显示器 画质字体模糊
  • ¥15 TLS1.2协议通信解密
  • ¥40 图书信息管理系统程序编写
  • ¥20 Qcustomplot缩小曲线形状问题
  • ¥15 企业资源规划ERP沙盘模拟
  • ¥15 树莓派控制机械臂传输命令报错,显示摄像头不存在
  • ¥15 前端echarts坐标轴问题
  • ¥15 ad5933的I2C
  • ¥15 请问RTX4060的笔记本电脑可以训练yolov5模型吗?
  • ¥15 数学建模求思路及代码