Files
the-way-to-go_ZH_CN/eBook/14.8.md
2017-01-12 20:33:00 +08:00

2.1 KiB
Raw Blame History

14.8 惰性生成器的实现

生成器是指当被调用时返回一个序列中下一个值的函数,例如:

    generateInteger() => 0
    generateInteger() => 1
    generateInteger() => 2
    ....

生成器每次返回的是序列中下一个值而非整个序列这种特性也称之为惰性求值只在你需要时进行求值同时保留相关变量资源内存和cpu这是一项在需要时对表达式进行求值的技术。例如生成一个无限数量的偶数序列要产生这样一个序列并且在一个一个的使用可能会很困难而且内存会溢出但是一个含有通道和go协程的函数能轻易实现这个需求。

在14.12的例子中我们实现了一个使用int型通道来实现的生成器。通道被命名为yieldresume,这些此经常在协程代码中使用。

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协程的开销可能会超过带来的性能增益。

这些原则可以概括为:通过巧妙地使用空接口、闭包和高阶函数,我们能实现一个通用的惰性生产器(这个应该放在一个工具包中实现)。

链接