Go 等待所有围棋程序完成

Go 等待所有围棋程序完成,go,concurrency,goroutine,Go,Concurrency,Goroutine,第一次使用围棋,尝试让围棋例程和WaitGroups工作 我有一个包含100行数据的CSV文件。(101包括收割台) 我有以下简单的代码: package main import ( "bufio" "fmt" "io" "os" "sync" "time" ) func main() { start := time.Now() numRows := 0 waitGroup := sync.WaitGroup{}

第一次使用围棋,尝试让围棋例程和
WaitGroups
工作

我有一个包含100行数据的CSV文件。(101包括收割台)

我有以下简单的代码:

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "sync"
    "time"
)

func main() {
    start := time.Now()
    numRows := 0

    waitGroup := sync.WaitGroup{}
    file, _ := os.Open("./data.csv")

    scanner := bufio.NewScanner(file)
    scanner.Scan() // to read the header

    for scanner.Scan() {
        err := scanner.Err()

        if err != nil && err != io.EOF {
            panic(err)
        }

        waitGroup.Add(1)

        go (func() {
            numRows++
            waitGroup.Done()
        })()
    }

    waitGroup.Wait()
    file.Close()

    fmt.Println("Finished parsing ", numRows)
    fmt.Println("Elapsed time in seconds: ", time.Now().Sub(start))
}
当我运行它时,
numRows
输出每次在94到100之间波动。我希望每次都是100。如果我在包含10行数据的CSV上运行相同的代码,它每次都会输出
10

在我看来,最后几次围棋没有及时结束

我尝试了以下失败的方法:

  • 使用
    CsvReader
    代替
    扫描仪
  • 移动
    waitGroup。将(1)
    添加到匿名函数下面
  • 将匿名func移出到包级别的作用域func中(并使用ptr传递内容)

我遗漏了什么?

在不同的goroutine中同时修改单个变量是不安全的。您对
numRows
的一些更新将丢失,有时您的程序可能会崩溃

使用互斥锁保护
numRows
变量,或使用其中一个函数以原子方式进行添加:

var numRows int32

// ...

    go (func() {
        atomic.AddInt32(&numRows, 1)
        waitGroup.Done()
    })()

您如何处理此代码:

for scanner.Scan() {
    err := scanner.Err()

    if err != nil && err != io.EOF {
        panic(err)
    }

    waitGroup.Add(1)

    go (func() {
        numRows++
        waitGroup.Done()
    })()
}
实际上,所有的工作都在一个主goroutine中完成,只有
numRows
increment使用单独的goroutine。我认为这可以简化为简单的增量:

for scanner.Scan() {
    err := scanner.Err()

    if err != nil && err != io.EOF {
        panic(err)
    }
    numRows++
}
如果您想模拟并行解析和管道,可以使用通道。只让一个goroutine负责计数器增量。每当另一个goroutine想要递增计数器时,它就会向该通道发送一条消息


在种族检测器下运行:-)毫无疑问,它可以简化,但我不认为这是问题的关键。是的,我只是分享了一些如何与ChannelsAh序列化访问的想法。这很有意义。我的代码非常脆弱,但关键是我在go中掌握了并发性,所以这将我推向了正确的方向。谢谢你已经说过了,这是有道理的。我想我现在开始更了解goroutines了。谢谢你对原子函数的了解。