python生成器的效率

时间:2015-08-01 13:07:35

标签: python performance generator

我正在编写一些软件来创建一个复杂的波形(实际上是一个声波)作为一个数组。从一些原始波形(正弦波等)开始,将有一些功能将它们组合起来创造更复杂的波浪,还有更多功能组合这些波浪等等。

看起来像是:

f(mult(sine(), env(square(), ramp()))

但更复杂。

这样做的一种方法是使每个函数成为一个生成器,这样整个函数树每个元素执行一次,每个生成器每次产生一个值。

数组可能有数百万个元素,而函数树可能很容易达到10个。这样做会让发电机效率低得离谱吗?

替代方案是为每个函数创建并返回整个数组。这可能会更有效,但也有缺点(实现更复杂,在计算结束之前没有结果,可能会占用大量内存)。

他们总是说你不应该试图再次猜测Python的效率,但是在这种情况下,生成器会花费很长时间吗?

2 个答案:

答案 0 :(得分:2)

在我看来,发电机非常适合这项任务。

某些信号具有有限的时间(如包络或斜坡),但其他一些信号是无限的(如振荡器)。

使用生成器你不应该担心这个方面,因为 - 像zip()函数 - 一个将振荡器与一个包络相结合(例如相乘)的函数,只会消耗来自振荡器gen的有限数量的项目,因为至少有一台发电机产生有限数量的样品。

然而,使用发电机是非常优雅和pythonic。

回想一下像这样的生成器:

def sine(freq):
    phase = 0.0
    while True:
        yield math.sin(phase)
        phase += samplerate/freq

只是这样一个类的语法糖:

class sine:
    def __init__(self, freq):
        self.freq = freq
        self.phase = 0.0

    def __iter__(self):
        return self

    def __next__(self):
        v = math.sin(self.phase)
        self.phase += samplerate/freq
        return v
        # for this infinite gen we never raise StopIteration()

因此,性能开销并不比您可以手工制作的任何其他解决方案(例如DSP处理中常用的块处理)。

也许你可以获得一些效率,如果不是产生单个样本,你就会产生样本块(例如,每次1024个样本)。

答案 1 :(得分:2)

生成器是惰性序列。只要您可以分段操作(元素方面或合理大小的块),它们就非常适合使用可能很长的序列。

这会降低您的峰值内存使用量。只是不要破坏它,然后将序列的所有元素存储在某处。