从通道读取多个goroutine导致错误的数据计数

时间:2019-01-01 09:20:16

标签: go concurrency goroutine

我正在研究一个程序,在该程序中我读取了一个csv文件并执行以下操作:

完整代码位于:Here

我的CSV文件位于: CSV file

问题是有时我获得正确的A和B计数,有时却获得错误的计数。

我认为我在Goroutine和渠道交流中做错了事。

当我评论第二个goroutine时,我得到了第一个goroutine的正确结果。但是,当我取消注释第二个Goroutine时,我会得到不正确的Goroutine 1和2输出。

任何人都可以解释我在做什么错吗?

另外,当我运行-race main.go时,结果向我显示了竞争状况。

func main() {
    input, err := os.Open("CSV.csv")
    if err != nil {
        fmt.Println("Error while opening CSV file.")
        return
    }
    defer input.Close()

    formattedStartDateRange,err := time.Parse(time.RFC3339, startDateRange)
    if err != nil {
        fmt.Println(err)
    }

    formattedendDateRange,err := time.Parse(time.RFC3339, endDateRange)
    if err != nil {
        fmt.Println(err)
    }

    reader := csv.NewReader(input)
    reader.FieldsPerRecord = -1
    files := make(map[string]chan []string)

    wg := &sync.WaitGroup{}

    var line []string
    for line, err = reader.Read(); err == nil; line, err = reader.Read() {
        ch, ok := files[line[0]]
        if ok {
            ch <- line
        } else {
            ch = make(chan []string, 8)
            ch <- line
            wg.Add(2) // Must wait for 2 calls to 'done' before moving on

            go func() {
                UserMapMutex.Lock()
                if (findNumberOfBuilds(formattedStartDateRange, formattedendDateRange, ch, wg)) {
                    totalBuildCount++
                }
                UserMapMutex.Unlock()
                wg.Done()
            }()

            go func() {
                UserMapMutex.Lock()
                countUserBuildFrequency(ch, wg)
                UserMapMutex.Unlock()
                wg.Done()
            }()


            files[line[0]] = ch
        }
    }


    if err.Error() != "EOF" {
        fmt.Println("Error while reading CSV file.")
        return
    }
    for _, ch := range files {
        close(ch)
    }
    wg.Wait()

    fmt.Println("Total Build executed from 1st November to 30th November =", totalBuildCount)
    fmt.Println("Total Build", userBuildFreq["5c00a8f685db9ec46dbc13d7"])
    fmt.Println("Done!")
}

1 个答案:

答案 0 :(得分:2)

在两种情况下,启动goroutine后都会立即调用wg.Done()。这意味着您的WaitGroup不在等待goroutine完成。请记住,当您调用goroutine时,调用过程将继续进行。完成操作后,尝试将wg.Done()调用 放入goroutine中。

go func(wg) {
    // do stuff
    wg.Done
}

OR

go func(wg) {
    defer wg.Done
    // do stuff
}