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

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

如何在 Go API 中并發運行函數,而不是順序運行函數?

如何在 Go API 中并發運行函數,而不是順序運行函數?

Go
料青山看我應如是 2022-08-01 11:07:51
在API中,如果我們需要查詢多個表,我們如何同時實現它,而不是遵循順序方式,即func sampleAPI(w http.ResponseWriter, r *http.Request) {    a, err := getFromATable();  //1    if err != nil {       w.WriteHeader(http.StatusInternalServerError)       return    }    b, err := getFromBTable();  //2    if err != nil {       w.WriteHeader(http.StatusInternalServerError)       return    }    c, err := getFromCTable();  //3    if err != nil {       w.WriteHeader(http.StatusInternalServerError)       return    }    .    .    .}我想同時調用上述函數1,2,3。我怎樣才能做到這一點
查看完整描述

3 回答

?
手掌心

TA貢獻1942條經驗 獲得超3個贊

使用錯誤通道進行同步

func sampleAPI(w http.ResponseWriter, r *http.Request) {

    chErr := make(chan error)


    var a correctType

    go func() {

        var err error

        a, err = getFromATable()

        chErr <- err

    }()


    var b correctType

    go func() {

        var err error

        b, err = getFromBTable()

        chErr <- err

    }()


    var c correctType

    go func() {

        var err error

        c, err = getFromCTable()

        chErr <- err

    }()


    var err error

    for i := 0; i < 3; i++ {

        if r := <-chErr; r != nil {

            err = r

        }

    }

    if err != nil {

        w.WriteHeader(http.StatusInternalServerError)

        // etc.

        return

    }


    // continue to do stuff with a, b, c

}

一些注意事項:

  • 每個 go 函數都必須向 添加一個值。確保它!如果沒有錯誤,則寫入(如果沒有錯誤,此示例將寫入)。chErrnilchErr

  • for 循環必須迭代與啟動 go 函數相同的數量。

  • for 循環確保所有函數都已完成(有或沒有錯誤),然后再繼續。

  • 使用錯誤進行同步很方便,因為它對于所有函數都是相同的類型。返回類型可能不同。如果我們需要在錯誤時取消,我們無論如何都需要將錯誤從goroutines中取回。

使用errgroup

正如 @Зелёный 在注釋中所建議的那樣,這里有一個使用(仍然)實驗包錯誤組的示例

func sampleAPI(w http.ResponseWriter, r *http.Request) {

    g, ctx := errgroup.WithContext(context.TODO())


    var a correctType

    g.Go(func() (err error) {

        a, err = getFromATable(ctx)

        return err

    })


    var b correctType

    g.Go(func() (err error) {

        b, err = getFromBTable(ctx)

        return err

    })


    var c correctType

    g.Go(func() (err error) {

        c, err = getFromCTable(ctx)

        return err

    })


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

        w.WriteHeader(http.StatusInternalServerError)

        // etc.

        return

    }


    // continue to do stuff with a, b, c

}

一些注意事項:

  • 這個檢查所有錯誤,并為您返回第一個錯誤。

  • 如果一個錯誤,它還會取消剩余的調用(因此ctx)

  • 它使用sync.WaitGroup

  • 缺點:它是一個額外的依賴項,因為它不是標準庫的一部分(尚未)。

使用WaitGroup

還可以使用 a 來等待所有函數都返回其結果。sync.WaitGroup

func sampleAPI(w http.ResponseWriter, r *http.Request) {

    var wg sync.WaitGroup

    wg.Add(3)


    var a correctType

    var errA error

    go func() {

        defer wg.Done()

        a, errA = getFromATable()

    }()


    var b correctType

    var errB error

    go func() {

        defer wg.Done()

        b, errB = getFromBTable()

    }()


    var c correctType

    var errC error

    go func() {

        defer wg.Done()

        c, errC = getFromCTable()

    }()


    wg.Wait()

    

    if errA != nil {

        w.WriteHeader(http.StatusInternalServerError)

        // etc.

        return

    }

    if errB != nil {

        w.WriteHeader(http.StatusInternalServerError)

        // etc.

        return

    }

    if errC != nil {

        w.WriteHeader(http.StatusInternalServerError)

        // etc.

        return

    }


    // continue to do stuff with a, b, c

}

一些注意事項:

  • 這里需要 3 個錯誤變量。

  • 您需要在 之后檢查所有3個錯誤變量,使其有點冗長。wg.Wait



查看完整回答
反對 回復 2022-08-01
?
慕碼人8056858

TA貢獻1803條經驗 獲得超6個贊

您還可以使用等待組來等待所有 api 調用完成,然后再繼續操作:


func sampleAPI(w http.ResponseWriter, r *http.Request) {

    var res1, res2, res3 myCustomType

    var err1, err2, err2 error


    var wg sync.WaitGroup

        wg.Add(3)


    go func() {

        defer wg.Done()

        res1, err1 = getFromATable();  //1

    }()


    go func() {

        defer wg.Done()

        res2, err2 = getFromBTable();  //2

    }()


    go func() {

        defer wg.Done()

        res3, err3 = getFromXTable();  //3

    }()


    wg.Wait()

}

進一步參考也 https://gobyexample.com/waitgroups 和 https://tutorialedge.net/golang/go-waitgroup-tutorial/


查看完整回答
反對 回復 2022-08-01
?
慕妹3146593

TA貢獻1820條經驗 獲得超9個贊

如果 a、b 和 c 是不同的類型,則可以嘗試以下方法。interface{}類型只是為了展示如何編碼,你可以根據自己的要求修改通道類型。


    aCh := make(chan interface{})

    bCh := make(chan interface{})

    cCh := make(chan interface{})

    defer close(aCh)

    defer close(bCh)

    defer close(cCh)

    

    go func() {

      a, _ := GetFromATable()

      aCh <- a

    }()

    go func() {

      b, _ := GetFromBTable()

      bCh <- b

    }()

    go func() {

      c, _ := GetFromCTable()

      cCh <- c

    }()


    fmt.Println(<- aCh, <- bCh, <- cCh)

如果所有三個輸出都處于同一類型,則只需使用單個通道或使用帶有 select 語句的 forever for 循環來處理流式處理要求。


查看完整回答
反對 回復 2022-08-01
  • 3 回答
  • 0 關注
  • 144 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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