首頁  >  文章  >  後端開發  >  在sync.WaitGroup goroutine中寫入chan

在sync.WaitGroup goroutine中寫入chan

PHPz
PHPz轉載
2024-02-09 17:00:10647瀏覽

在sync.WaitGroup goroutine中写入chan

php小編柚子在這裡為大家介紹在sync.WaitGroup goroutine中寫入chan的方法。在並發程式設計中,sync.WaitGroup是一種非常有用的同步機制,它可以等待一組goroutine的執行完成。然而,有時我們需要在goroutine執行完畢後,將結果寫入到一個chan中,以供其他goroutine消費。本文將詳細介紹如何在sync.WaitGroup goroutine中實現這項功能,讓我們一起來看看吧!

問題內容

我正在從 API 端點取得項目清單。然後,對於每個項目,我都會發出另一個 API 請求以獲取有關單一項目的資料。

我無法同時對每個專案發出第二個 API 請求,因為我的 API 令牌有速率限制,如果我同時發出太多請求,我會受到限制。

但是,初始 API 回應資料可以分為多個頁面,這使我能夠同時處理資料頁面。

經過一些研究,下面的程式碼完全符合我的要求:

func main() {
    // pretend paginated results from initial API request
    page1 := []int{1, 2, 3}
    page2 := []int{4, 5, 6}
    page3 := []int{7, 8, 9}
    pages := [][]int{page1, page2, page3}

    results := make(chan string)

    var wg sync.WaitGroup
    for i := range pages {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            for j := range pages[i] {
                // simulate making additional API request and building the report
                time.Sleep(500 * time.Millisecond)

                result := fmt.Sprintf("Finished creating report for %d", pages[i][j])
                results <- result
            }

        }(i)
    }

    go func() {
        wg.Wait()
        close(results)
    }()

    for result := range results {
        fmt.Println(result)
    }
}

我想了解為什麼它能發揮作用:

go func() {
    wg.Wait()
    close(results)
}()

我的第一次嘗試沒有成功——我想我可以在wg.Wait() 之後遍歷通道,並且我會在結果寫入results 通道時讀取結果。

func main() {
    // pretend paginated results from initial API request
    page1 := []int{1, 2, 3}
    page2 := []int{4, 5, 6}
    page3 := []int{7, 8, 9}
    pages := [][]int{page1, page2, page3}

    results := make(chan string)

    var wg sync.WaitGroup
    for i := range pages {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            for j := range pages[i] {
                // simulate making additional API request and building the report
                time.Sleep(500 * time.Millisecond)

                result := fmt.Sprintf("Finished creating report for %d", pages[i][j])
                results <- result
            }

        }(i)
    }

    // does not work
    wg.Wait()
    close(results)

    for result := range results {
        fmt.Println(result)
    }
}

解決方法

在您的第一次嘗試:

  1. 主 goroutine 使 3 個 goroutine 將值放入結果通道中。
  2. 主協程等待所有協程完成。
  3. 其中一個 goroutine 將一個值放入結果通道中並填滿通道(通道大小為 1 個字串)。
  4. 現在所有三個 goroutine 都無法再將值放入結果通道並進入睡眠狀態,直到結果通道被釋放。
  5. 所有 goroutine 都處於睡眠狀態。你陷入了僵局。

在第二次嘗試:

  1. 主 goroutine 包含 4 個 goroutine。
  2. 3 個 goroutine 將值放入結果通道中。
  3. 其他 goroutine(我稱之為第 4 個)等待這 3 個 goroutine 結束。
  4. 同時主協程等待結果通道中的值(for 迴圈)
  5. 在這種情況下,如果其中一個 goroutine 在結果通道中放入一個值,則會阻塞其餘的三個 goroutine;主 Goroutine 將值從結果通道中取出,從而解除對其他 Goroutine 的阻塞。
  6. 因此,所有 3 個 goroutine 都放入各自的值並結束
  7. 然後第四個 goroutine 關閉通道
  8. 主 Goroutine 結束其 for 迴圈。

以上是在sync.WaitGroup goroutine中寫入chan的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除