mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-11-13 09:16:10 +08:00
2.1 KiB
2.1 KiB
14.8 惰性生成器的实现
生成器是指当被调用时返回一个序列中下一个值的函数,例如:
generateInteger() => 0
generateInteger() => 1
generateInteger() => 2
....
生成器每次返回的是序列中下一个值而非整个序列;这种特性也称之为惰性求值:只在你需要时进行求值,同时保留相关变量资源(内存和cpu):这是一项在需要时对表达式进行求值的技术。例如,生成一个无限数量的偶数序列:要产生这样一个序列并且在一个一个的使用可能会很困难,而且内存会溢出!但是一个含有通道和go协程的函数能轻易实现这个需求。
在14.12的例子中,我们实现了一个使用int型通道来实现的生成器。通道被命名为yield和resume,这些此经常在协程代码中使用。
Listing 14.12-lazy evaluation.go
package main
import (
"fmt"
)
var resume chan int
func integers() chan int {
yield := make(chan int)
count := 0
go func() {
for {
yield <- count
count++
}
}()
return yield
}
func generateInteger() int {
return <-resume
}
func main() {
resume = integers()
fmt.Println(generateInteger()) //=> 0
fmt.Println(generateInteger()) //=> 1
fmt.Println(generateInteger()) //=> 2
}
有一个细微的区别是从通道读取的值可能会是稍早前产生的,并不是在程序被调用时生成的。如果确实需要这样的行为,就得实现一个请求响应机制。当生成器生成数据的过程是计算密集型且各个结果的顺序并不重要时,那么就可以将生成器放入到go协程实现并行化。但是得小心,使用大量的go协程的开销可能会超过带来的性能增益。
这些原则可以概括为:通过巧妙地使用空接口、闭包和高阶函数,我们能实现一个通用的惰性生产器(这个应该放在一个工具包中实现)。
链接
- 目录
- 上一节:新旧模型对比:任务和worker
- 下一节:Implementing Futures