1。運行每個範例:不要只閱讀程式碼。輸入它,運行它,然後觀察其行為。 ⚠️ 這個系列如何進行?
2。實驗和打破常規: 刪除睡眠並看看會發生什麼,更改通道緩衝區大小,修改 goroutine 計數。
打破東西會教你它們是如何運作的
3。關於行為的原因: 在執行修改後的程式碼之前,嘗試預測結果。當您看到意外行為時,請停下來思考原因。挑戰解釋。
4。建立心理模型:每個視覺化代表一個概念。嘗試為修改後的程式碼繪製自己的圖表。
在上一篇文章中,我們探討了 goroutine 和通道的基礎知識,它們是 Go 並發的構建塊。閱讀此處:
現在,讓我們看看這些原語如何組合起來形成解決現實世界問題的強大模式。
在這篇文章中,我們將介紹生成器模式並嘗試將它們視覺化。因此,讓我們做好準備,因為我們將親手完成整個過程。
生成器就像一個噴泉,不斷產生我們可以在需要時使用的值。
在 Go 中,它是一個產生值流並透過通道發送它們的函數,允許程式的其他部分按需接收這些值。
讓我們來看一個例子:
// 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) } }
在這個例子中,我們的生成器函數做了三件關鍵的事情:
逐行讀取大檔案:
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 }
您可以在資料仍在產生時開始處理資料。
非阻塞執行:產生和處理同時發生
記憶體效率:一次可以產生並處理一個值,無需立即儲存在記憶體中
無限序列:可以產生無限序列而不會出現記憶體問題
反壓處理:如果你的消費者很慢,生成器自然會減慢(由於通道阻塞),防止記憶體過載。
// 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) } }
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 }
// 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 }
// 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中文網其他相關文章!