Go 併發可視化解釋 - sync-WaitGroup

場景

Avito 是一名校車司機,他幫助 4 個 Gopher 孩子上學。每天,Avito 在他們的社區等待孩子們。他不知道孩子們需要多長時間,但他確切地知道有 4 個孩子他需要等待。

當一個孩子準備好時,他 / 她會說:Done(),將計數器減 1。Avito 仍然被阻塞,因爲計數器仍然大於 0。他必須等到所有其他孩子準備好。

如果有兩個孩子同時準備好,它們的同時準備會導致WaitGroup出現不一致嗎?絕對不會。與sync包中的大多數其他組件一樣,WaitGroup具有內置的同步機制,以處理併發。因此,計數器減少了準備好的孩子數量。

在最後一個孩子準備好後,Avito 啓動引擎,將他們送到學校。

就是這樣!正如我所說,sync.WaitGroup很簡單。

超時

如果一個孩子花費太多時間準備,他們會不會因此遲到?如果 Avito 在時間到達時不管怎樣都開始行駛會更好嗎?嗯,Golang 傾向於保持一切儘可能簡潔,因此與其他編程語言中的CountDownLatch(例如 Java 中的)不同,sync.WaitGroup默認情況下不支持超時。在這種情況下,選擇語句可能會有所幫助。

func main() {
    wg := sync.WaitGroup{}
    wg.Add(1)
    go func() {
        defer wg.Done()
        time.Sleep(5 * time.Second)
    }()
    done := make(chan bool)
    go func() {
        wg.Wait()
        close(done)
    }()
    select {
    case <-done:
        log.Println("All done")
    case <-time.After(1 * time.Second):
        log.Println("Hit timeout")
    }
}

孩子等待

在上面的示例中,Avito(主 Goroutine)等待孩子(子 Goroutines)。當我們希望子 Goroutines 等待主 Goroutine 時,WaitGroup也可以使用。想象一下孩子們正在進行體育課。Torcher - 體育老師,在學生中主持比賽。他向WaitGroupAdd(1),並要求所有孩子在相同的WaitGroupWait()

當 Torcher 調用wg.Done()時,計數器變爲 0,允許所有孩子同時開始奔跑。

展示你的代碼!

package main
import (
    "log"
    "sync"
    "time"
)
func main() {
    kids := []string{"Partier", "Stringer", "Candier", "Swimmer"}
    wg := sync.WaitGroup{}
    wg.Add(len(kids))
    for _, kid := range kids {
        go func(name string) {
            defer wg.Done()
            prepare(name)
        }(kid)
    }
    log.Printf("Avito: I'm waiting for %d kids\n", len(kids))
    wg.Wait()
    log.Println("Avito: The kids are all ready, go!")
}
func prepare(name string) {
    log.Printf("%v: I'm preparing for school\n", name)
    time.Sleep(2 * time.Second)
    log.Printf("%v: I'm ready\n", name)
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/1DQxrwgLNxb5M1vXmEZ9kg