我正在编写一些软件来创建一个复杂的波形(实际上是一个声波)作为一个数组。从一些原始波形(正弦波等)开始,将有一些功能将它们组合起来创造更复杂的波浪,还有更多功能组合这些波浪等等。
看起来像是:
f(mult(sine(), env(square(), ramp()))
但更复杂。
这样做的一种方法是使每个函数成为一个生成器,这样整个函数树每个元素执行一次,每个生成器每次产生一个值。
数组可能有数百万个元素,而函数树可能很容易达到10个。这样做会让发电机效率低得离谱吗?
替代方案是为每个函数创建并返回整个数组。这可能会更有效,但也有缺点(实现更复杂,在计算结束之前没有结果,可能会占用大量内存)。
他们总是说你不应该试图再次猜测Python的效率,但是在这种情况下,生成器会花费很长时间吗?
答案 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)
生成器是惰性序列。只要您可以分段操作(元素方面或合理大小的块),它们就非常适合使用可能很长的序列。
这会降低您的峰值内存使用量。只是不要破坏它,然后将序列的所有元素存储在某处。