首頁 > 後端開發 > Golang > Go 中的生成器並發模式:綜合指南

Go 中的生成器並發模式:綜合指南

Mary-Kate Olsen
發布: 2025-01-04 06:16:40
原創
294 人瀏覽過

⚠️ 這個系列如何進行?

1。運行每個範例:不要只閱讀程式碼。輸入它,運行它,然後觀察其行為。
2。實驗和打破常規: 刪除睡眠並看看會發生什麼,更改通道緩衝區大小,修改 goroutine 計數。
打破東西會教你它們是如何運作的
3。關於行為的原因: 在執行修改後的程式碼之前,嘗試預測結果。當您看到意外行為時,請停下來思考原因。挑戰解釋。
4。建立心理模型:每個視覺化代表一個概念。嘗試為修改後的程式碼繪製自己的圖表。

Generator Concurrency Pattern in Go: A Comprehensive Guide

在上一篇文章中,我們探討了 goroutine 和通道的基礎知識,它們是 Go 並發的構建塊。閱讀此處:

Generator Concurrency Pattern in Go: A Comprehensive Guide

理解和視覺化 Golang 中的 Goroutine 和 Channel

Souvik Kar Mahapatra ・ 12 月 20 日

#去 #程式設計 #學習 #教程

現在,讓我們看看這些原語如何組合起來形成解決現實世界問題的強大模式。

在這篇文章中,我們將介紹生成器模式並嘗試將它們視覺化。因此,讓我們做好準備,因為我們將親手完成整個過程。

Generator Concurrency Pattern in Go: A Comprehensive Guide

生成器模式

生成器就像一個噴泉,不斷產生我們可以在需要時使用的值。

在 Go 中,它是一個產生值流並透過通道發送它們的函數,允許程式的其他部分按需接收這些值。

Generator Concurrency Pattern in Go: A Comprehensive Guide

讓我們來看一個例子:

// generateNumbers creates a generator that produces numbers from 1 to max
func generateNumbers(max int) chan int {
    // Create a channel to send numbers
    out := make(chan int)

    // Launch a goroutine to generate numbers
    go func() {
        // Important: Always close the channel when done
        defer close(out)

        for i := 1; i <= max; i++ {
            out <- i  // Send number to channel
        }
    }()

    // Return channel immediately
    return out
}

// Using the generator
func main() {
    // Create a generator that produces numbers 1-5
    numbers := generateNumbers(5)

    // Receive values from the generator
    for num := range numbers {
        fmt.Println("Received:", num)
    }
}
登入後複製
登入後複製

在這個例子中,我們的生成器函數做了三件關鍵的事情:

  1. 建立一個通道來傳送值
  2. 啟動 goroutine 來產生值
  3. 立即回頻道供消費者使用

為什麼要使用生成器?

  1. 將價值生產與消費分開
  2. 按需產生值(惰性求值)
  3. 可以表示無限序列而不消耗無限記憶體
  4. 允許並發生產和消費值

現實世界的用例

逐行讀取大檔案:

func generateLines(filename string) chan string {
    out := make(chan string)
    go func() {
        defer close(out)
        file, err := os.Open(filename)
        if err != nil {
            return
        }
        defer file.Close()

        scanner := bufio.NewScanner(file)
        for scanner.Scan() {
            out <- scanner.Text()
        }
    }()
    return out
}
登入後複製
登入後複製

現在您可能會想,它有什麼特別之處?我們可以做同樣的事情,例如產生資料序列或在沒有 goroutine 的情況下逐行讀取。是不是太過分了?讓我們嘗試視覺化這兩種情況:

沒有 goroutine

// Traditional approach
func getNumbers(max int) []int {
    numbers := make([]int, max)
    for i := 1; i <= max; i++ {
        numbers[i-1] = i
        // Imagine some heavy computation here
        time.Sleep(100 * time.Millisecond)
    }
    return numbers
}
登入後複製
登入後複製

這裡需要等待一切準備就緒才可以開始處理。

帶有 goroutine

// Generator approach
func generateNumbers(max int) chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for i := 1; i <= max; i++ {
            out <- i
            // Same heavy computation
            time.Sleep(100 * time.Millisecond)
        }
    }()
    return out
}
登入後複製
登入後複製

您可以在資料仍在產生時開始處理資料。

Generator Concurrency Pattern in Go: A Comprehensive Guide

生成器模式的主要優點:

  1. 非阻塞執行:產生和處理同時發生

  2. 記憶體效率:一次可以產生並處理一個值,無需立即儲存在記憶體中

  3. 無限序列:可以產生無限序列而不會出現記憶體問題

  4. 反壓處理:如果你的消費者很慢,生成器自然會減慢(由於通道阻塞),防止記憶體過載。

// generateNumbers creates a generator that produces numbers from 1 to max
func generateNumbers(max int) chan int {
    // Create a channel to send numbers
    out := make(chan int)

    // Launch a goroutine to generate numbers
    go func() {
        // Important: Always close the channel when done
        defer close(out)

        for i := 1; i <= max; i++ {
            out <- i  // Send number to channel
        }
    }()

    // Return channel immediately
    return out
}

// Using the generator
func main() {
    // Create a generator that produces numbers 1-5
    numbers := generateNumbers(5)

    // Receive values from the generator
    for num := range numbers {
        fmt.Println("Received:", num)
    }
}
登入後複製
登入後複製

常見陷阱和解決方案

  1. 忘記關閉頻道
func generateLines(filename string) chan string {
    out := make(chan string)
    go func() {
        defer close(out)
        file, err := os.Open(filename)
        if err != nil {
            return
        }
        defer file.Close()

        scanner := bufio.NewScanner(file)
        for scanner.Scan() {
            out <- scanner.Text()
        }
    }()
    return out
}
登入後複製
登入後複製
  1. 不處理錯誤
// Traditional approach
func getNumbers(max int) []int {
    numbers := make([]int, max)
    for i := 1; i <= max; i++ {
        numbers[i-1] = i
        // Imagine some heavy computation here
        time.Sleep(100 * time.Millisecond)
    }
    return numbers
}
登入後複製
登入後複製
  1. 資源洩漏:將生成器與資源(如檔案)一起使用時,請確保正確清理:
// Generator approach
func generateNumbers(max int) chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for i := 1; i <= max; i++ {
            out <- i
            // Same heavy computation
            time.Sleep(100 * time.Millisecond)
        }
    }()
    return out
}
登入後複製
登入後複製

這就是生成器模式的全部。接下來是管道並發模式。請繼續關注,清除您對 Golang 並發的概念。

我錯過了什麼嗎?有疑問嗎?有什麼有趣的事可以分享嗎?歡迎大家提出意見。

以上是Go 中的生成器並發模式:綜合指南的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板