为了账号安全,请及时绑定邮箱和手机立即绑定

所有 goroutine 在我的异步代码中都处于休眠状态

所有 goroutine 在我的异步代码中都处于休眠状态

Go
米琪卡哇伊 2022-07-11 15:51:14
我读了这个,这个和这个,但没有一个能解决我的问题..我正在尝试异步读取 2 个文件,所以我写了以下内容://readlines.gopackage mainimport (    "bufio"    "os")// readLines reads a whole file into memory// and returns a slice of its lines.func readLines(path string) ([]string, error) {    file, err := os.Open(path)    if err != nil {        return nil, err    }    defer file.Close()    var lines []string    scanner := bufio.NewScanner(file)    for scanner.Scan() {        lines = append(lines, scanner.Text())    }    return lines, scanner.Err()}并将其称为:package mainimport (    "fmt"    "os"    "github.com/gocarina/gocsv")func (s *stocks) Read() {    fmt.Println("Reading")    stockFile, err := os.OpenFile("current_invenory.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)    if err != nil {        panic(err)    }    defer stockFile.Close()    stocks := []systemStock{}    if err := gocsv.UnmarshalFile(stockFile, &stocks); err != nil { // Load stocks from file        panic(err)    }    *s = stocks}package mainimport (    "fmt"    "os"    "github.com/gocarina/gocsv")func (t *transactions) Read() {    fmt.Println("Reading")    trxFile, err := os.OpenFile("current_transactions.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)    if err != nil {        panic(err)    }    defer trxFile.Close()    trx := []systemTransactions{}    if err := gocsv.UnmarshalFile(trxFile, &trx); err != nil { // Load stocks from file        panic(err)    }    *t = trx}以上工作非常好:    stock := stocks{}     trx := transactions{}    stock.Read()    trx.Read()    for _, s := range stock {            fmt.Println("Hello", s.Code)    }但是fatal error: all goroutines are asleep - deadlock!当我尝试将它们读取为时给出错误:    cs, ct := readData()    for _, s := range cs {        fmt.Println("Hello", s.Code)    }    for _, t := range ct {        fmt.Println("Hello trx of ", t.Code)    }所以这个错误与我在最后一个块中犯的错误(或不明白)有关~
查看完整描述

1 回答

?
森栏

TA贡献1810条经验 获得超5个赞

为了同时运行这些Read方法,这些方法需要有一种在它们完成执行时发出信号的方式。这可以通过多种方式完成,但这里有两种需要对代码进行最少修改的方式。stockstransactions


解决方案 1


使用sync.WaitGroup包。使用这个包,Read方法在执行完成后应该执行wg.Done()语句。它应该看起来像这样:


func (s *stocks) Read(wg *sync.WaitGroup) {

    defer wg.Done()

    fmt.Println("Reading")

    stockFile, err := os.OpenFile("current_invenory.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)

    if err != nil {

        panic(err)

    }

    defer stockFile.Close()

    stocks := []systemStock{}

    if err := gocsv.UnmarshalFile(stockFile, &stocks); err != nil { // Load stocks from file

        panic(err)

    }


    *s = stocks

}


func (t *transactions) Read(wg *sync.WaitGroup) {

    defer wg.Done()

    fmt.Println("Reading")

    trxFile, err := os.OpenFile("current_transactions.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)

    if err != nil {

        panic(err)

    }

    defer trxFile.Close()

    trx := []systemTransactions{}

    if err := gocsv.UnmarshalFile(trxFile, &trx); err != nil { // Load stocks from file

        panic(err)

    }


    *t = trx

}


func readData() (stocks, transactions) {

    var wg sync.WaitGroup

    wg.Add(2)


    stock := stocks{}

    trx := transactions{}


    go stock.Read(&wg)

    go trx.Read(&wg)


    wg.Wait()


    return stock, trx

}

解决方案 2


这种方法使用golang.org/x/sync/errgroup包。在这种情况下,您不需要自己处理同步和信令,但是使用errgroup.Go方法添加的函数需要具有严格的func() error签名。您的代码应如下所示:


func (s *stocks) Read() error {

        fmt.Println("Reading")

        stockFile, err := os.OpenFile("current_invenory.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)

        if err != nil {

            return err

        }

        defer stockFile.Close()

        stocks := []systemStock{}

        if err := gocsv.UnmarshalFile(stockFile, &stocks); err != nil { // Load stocks from file

            return err

        }

    

        *s = stocks

        return nil

    }

    

    func (t *transactions) Read() error {

        fmt.Println("Reading")

        trxFile, err := os.OpenFile("current_transactions.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)

        if err != nil {

            return err

        }

        defer trxFile.Close()

        trx := []systemTransactions{}

        if err := gocsv.UnmarshalFile(trxFile, &trx); err != nil { // Load stocks from file

            return err

        }

    

        *t = trx

        return nil

    }

    

    func readData() (stocks, transactions) {

        g, _ := errgroup.WithContext(context.Background())

    

        stock := stocks{}

        trx := transactions{}

    

        g.Go(stock.Read)

        g.Go(trx.Read)

    

        if err:= g.Wait(); err != nil {

           panic(err)

        }

    

        return stock, trx

    }

解决方案 3


当您开始从每个 CSV 读取时,您(正确地)将 1 添加到等待组,使等待组的内部计数器变为 2,但是 wg.Wait() 将等到该计数器下降到零并且您没有任何调用 wg.Done() 来做到这一点。我建议将 go stock.Read() 更改为:


go func() {

    defer wg Done()

    stock.Read()

}()

因此,完整的工作代码是:


func readData() (stocks, transactions) {

    var wg sync.WaitGroup


    stock := stocks{}

    trx := transactions{}


    wg.Add(1)

    go func() {

        defer wg.Done()

        stock.Read()

    }()

    wg.Add(1)

    go func() {

        defer wg.Done()

        trx.Read()

    }()


    wg.Wait()


    return stock, trx

}


查看完整回答
反对 回复 2022-07-11
  • 1 回答
  • 0 关注
  • 127 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信