亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

所有 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 關注
  • 142 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號