首頁  >  文章  >  後端開發  >  扇出模式

扇出模式

PHPz
PHPz原創
2024-07-28 11:10:22514瀏覽

Fanout Pattern

讓我們快速瀏覽一下 Go 中的扇出模式。一般來說,扇出用於同時執行多個任務。

例如,假設您有一個資料管道,並且您想要處理各個項目。我們可以使用 go 例程和通道在收到項目時將其拆分,然後處理各個項目(例如放入 dB)。

這是一個易於實現的簡單模式;但你需要管理通道以防止死鎖。

// produce is simulating our single input as a channel
func produce(id int) chan int {
    ch := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            ch <- rand.Intn(20)
        }
        fmt.Printf("producer %d done\n", id)
        close(ch) // this is important!!!
    }()
    return ch
}

func worker(id int, jobs chan int, wg *sync.WaitGroup) {
    for value := range jobs {
        odd := "even"
        if (value & 1) == 1 {
            odd = "odd"
        }
        fmt.Printf("worker: %d, got %d is %s\n", id, value, odd)
    }
    wg.Done()
}

func main() {
    inputCh := produce(1)

    numWorkers := 3
    jobs := make(chan int)

    // split input into individual jobs
    go func() {
        for value := range inputCh {
            jobs <- value
        }
        close(jobs) // this is important!!!
    }()

    // fan-out
    var wg sync.WaitGroup
    for i := 0; i < numWorkers; i++ {
        wg.Add(1)
        go worker(i, jobs, &wg)
    }
    wg.Wait()

    fmt.Println("done")
}

這裡的主要想法是有一個資料序列需要由固定數量的worker來操作。

對於輸入,我們建立一個隨機數序列並將它們放入通道中。我們將他們轉移到另一個管道,工人們將從中奪走他們的「工作」。

在此範例中,並非絕對有必要將輸入移至作業通道。我們可以輕鬆地讓工作人員從輸入通道中拉出;這裡只是為了清楚起見而這樣做。

然後我們將固定數量的工作線程作為 goroutine 發送出去。每個工作人員將從作業通道中拉出,直到沒有更多資料需要處理,此時它向 WaitGroup 發出信號,表明其已完成。

主執行緒使用 WaitGroup 來確保它在所有工作人員完成之前不會完成,即所有作業都已處理完畢。

需要提到的一個關鍵點是,此模式不會對處理輸入序列的順序做出任何保證。在很多情況下這可能沒問題。例如,輸入序列是包含自己的時間戳記的資料記錄,目標是將記錄儲存在 dB 中。在這種情況下,扇出是可以接受的。

最後一點,一旦序列中的所有資料都已發送,您將看到一些有關關閉通道的註釋。這很關鍵。一旦沒有更多數據,從通道中提取的範圍運算子就會休眠。您可以透過註解掉一個將導致死鎖情況的 close() 語句來驗證這一點。 Goroutine 和 Channel 非常強大,但你必須明智地使用它們。

你會做什麼不同的事情?我們如何改進這個例子?請在下面留下您的評論。

謝謝!

這篇文章以及本系列所有文章的程式碼可以在這裡找到

以上是扇出模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn