【问题标题】:Efficiency of generators发电机的效率
【发布时间】:2015-10-24 01:52:47
【问题描述】:

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

它可能看起来像:

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

但要复杂得多。

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

数组可能有几百万个元素,函数树很容易有 10 深。生成器这样做会不会效率低得离谱?

另一种方法是让每个函数创建并返回整个数组。这可能会更有效,但也有缺点(实现更混乱,在计算结束之前没有可用的结果,可能会占用大量内存)。

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

【问题讨论】:

  • 我将成为“他们”中的一员:您不应该尝试第二次猜测 Python 的效率。 试试吧。计时。如果您的实际事物过于复杂,请将其简化到足以得到一个体面的想法。一旦你断定没有太大区别并且它们都相当慢,请考虑 numpy 是否适合你的用例。
  • 编写代码并计时。听起来您的大部分代码都是数学函数等。所以如果你发现它很慢,用数组和最后一个 return 来改变 yield 返回应该不难
  • 避免过早优化。只要您不犯重大错误(例如,在大型列表上使用线性搜索而不是字典查找),如果您坚持常见的 Python 习语并且 Python 是一个合适的工具,那么您应该没问题。尤其是如果您正在编写一个供自己使用的工具,那么优化开发人员时间比从运行时缩短几分之一秒更重要。
  • 我必须同意@JohnColeman 的观点,即您是否可以选择像 Mathematica 或 Maple (Maplesoft) 这样更专注于数学和工程的东西来解决这个问题。这些软件包中的任何一个都可能具有更好的优化来处理您要完成的任务。虽然这两个选项都是商业性的,但如果您在学术环境中,那么它们通常具有站点许可证或软件包的学术定价,以降低它们过于昂贵的价格。
  • 目前我只是想避免犯下重大错误并最终导致速度慢得离谱的事情,看起来应该没问题。 Python 在这方面不会很快,但看起来我能够以比实时更快的速度创建大多数声音,这目前已经足够了。

标签: python performance generator


【解决方案1】:

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

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

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

然而,使用生成器是非常优雅和 Python 的。

回想一下这样的生成器:

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 个样本),也许您可​​以获得一些效率。

【讨论】:

  • 我编写了一些代码来尝试 3 种解决方案 - 产生每个样本,产生每 n 个样本,并一次处理整个数组。毫无疑问,产生每个样本会慢一些(5 秒而不是 3.5 秒),但对于实验来说是可以的。简化编码不仅仅是弥补它,而且我认为当我开始使用更复杂的函数时,百分比差异会减少。谢谢。
【解决方案2】:

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

这会减少您的内存使用高峰。只是不要在将序列的所有元素存储在某个地方时破坏它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多