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中文网其他相关文章!