我使用以下代码进行一些即时声音处理/分析。它工作,但真的很慢(与计划的速度相比)。我添加了一些时间标记来找出问题所在,根据它们不应该有任何问题。对于所有三个计算时间,典型的持续时间(见下文)<0.01秒,但是仍然需要大约一秒来完成循环。问题在哪里?
修改:请注意,时间测量不是真正的问题。为了证明:MyPeaks
基本上只能找到相当短的FFT的最大值 - 没什么代价。即使这些例程被注释掉,问题仍然存在。
等
import pyaudio
import struct
import mute_alsa
import time
import numpy as np
from Tkinter import *
def snd_process(k=0):
if k<1000:
t0=time.clock()
data = stream.read(CHUNK)
t1=time.clock()
fl=CHUNK
int_data = struct.unpack("%sh" %str(fl),data)
ft=np.fft.fft(int_data)
ft=np.fft.fftshift(ft)
ft=np.abs(ft)
t2=time.clock()
pks=MyPeaks(np.log(ft))
freq_out.configure(text=str(pks))
t3=time.clock()
print t1-t0, t2-t1, t3-t2
master.after(1, lambda: snd_process(k+1))
CHUNK = 8000
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 4000
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
#Tkinter stuff
master=Tk()
button_play=Button(master, command=snd_process, bg="yellow", text="Analyze")
button_play.grid(row=0, column=0)
freq_out = Label(master)
freq_out.grid(row=0, column=1)
freq_out.configure(text='base')
mainloop()
答案 0 :(得分:4)
您正在tk主线程中安排1000个回调;对于每个回调,您使用1 ms延迟(after()
的第一个参数)。这意味着最后一个循环将在第一个循环1000毫秒(1秒)后开始。
也许循环仍然需要大约一秒才能完成。
因此,请尝试使用after_idle()
。我认为你真的不需要加速声音处理算法因为np
已经非常有效了。
<强> [编辑] 强> 惊喜!你是在每次迭代时从音频通道读取1秒8000字节,16位格式,4000帧速率。你需要一秒钟才能拥有它。
答案 1 :(得分:2)
将I / O和计算压缩到主循环就像是经典的解决方案。但也有其他选择。
在第二个帖子中进行音频采集和计算。由于I / O和numpy都应该释放GIL,因此它可能是一个很好的选择。这里有一个警告。由于像TKinter这样的GUI工具包通常不是多线程安全的,因此你应该不从第二个线程进行Tkinter调用。但您可以设置一个使用after
调用的函数来检查计算的进度,并每隔100毫秒更新一次UI。
在另一个multiprocessing.Process
中进行音频采集和计算。这使它与GUI完全分离。您必须设置一个通信渠道,例如: Queue
将pks
发送回主进程。您应该使用after
函数检查Queue
是否有可用数据,如果是,则更新显示。
答案 2 :(得分:-1)
根据您运行的操作系统,您可能会测量实际的“挂钟”时间。有关详细信息,请参阅此处http://pythoncentral.io/measure-time-in-python-time-time-vs-time-clock/。请注意,对于python 3.3,不推荐使用time.clock,建议使用time.process_time()或time.perf_counter()。