发电机的效率

4
我正在编写一些软件,用于创建一个复杂的波形(实际上是声波)作为数组。从一些原始波形(如正弦波等)开始,将会有一些函数来组合它们,以创建更加复杂的波形,还有更多的函数来组合这些波形等等。
可能看起来像这样:
f(mult(sine(), env(square(), ramp()))

但是这个过程要复杂得多。

一种方法是将每个函数都变成生成器,这样整个函数树每次执行一个元素时就会执行一次,并且每个生成器每次都会产生一个值。

该数组可能有几百万个元素,而函数树可能很深。使用生成器会非常低效吗?

另一种选择是让每个函数创建并返回整个数组。这种方法可能更有效,但也有缺点(实现较为混乱,直到计算结束才能获得结果,可能会使用大量内存)。

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


5
我会成为“他们”中的一员:你不应该试图猜测Python的效率。尝试一下。计时它。如果你的实际事物过于复杂,简化它以获得一个合理的想法。一旦你得出结论认为它们之间没有太大差别且都相当缓慢,那么请考虑NumPy是否适合你的用例。 - lvc
编写代码并计时。听起来你的大部分代码都是数学函数之类的。因此,如果你发现它太慢了,改变yield返回和最后的返回为数组应该不难。 - Rasmus Damgaard Nielsen
1
避免过早优化。只要你不犯重大错误(例如在大型列表上使用线性搜索而不是字典查找),如果你坚持使用常见的Python习惯用法,并且Python是一个合适的工具,那么你应该没问题。特别是当你为自己编写工具时,优化开发时间比从运行时间中节省几分之一更为重要。 - John Coleman
我必须同意@JohnColeman的看法,质疑您是否不应该选择更加数学和工程化的软件,例如Mathematica或Maple(Maplesoft)来解决这个问题。这两个软件包中的任何一个都可能具有更好的优化功能,以处理您要完成的任务。虽然这两个选项都是商业软件,但如果您在学术环境中,则通常会有站点许可证或学术定价,使它们的价格不那么昂贵。 - AMR
目前我只是试图避免犯下重大错误,以免最终得到一个极其缓慢的东西,看起来应该没问题。Python 不会非常快,但看起来我能够以超过实时的速度创建大多数声音,这已经足够好了。 - Martin McBride
1
也许现在的情况与2015年不同,但是numpy是数学软件Mathematica和Maple的流行开源替代品,很可能已经在学术界超过了这两者。 - T.C. Proctor
2个回答

2
生成器是一种惰性序列。它们非常适合用于具有可能非常长的序列的情况,只要您可以分段操作(每个元素或适当大小的块)。这将倾向于减少峰值内存使用量。只需不要通过在某个地方存储序列的所有元素来破坏该功能即可。

1

在我看来,生成器非常适合这个任务。

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

使用生成器,您不必担心这个方面,因为像zip()函数一样,将一个振荡器与一个包络组合(例如相乘),只会从振荡器生成器中消耗有限数量的项,因为至少有一个生成器产生有限数量的样本。

然而,使用生成器非常优雅和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
我写了一些代码来尝试三种解决方案——每个样本都产生,每n个样本产生一次,以及一次处理整个数组。毫无疑问,每个样本产生的速度要慢一些(5秒而不是3.5秒),但对于实验来说还可以接受。简化编码比它更弥补了这一点,我认为当我开始使用更复杂的函数时,%的差异将会减少。谢谢。 - Martin McBride

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接