pygtk GUI因pyjack线程而冻结

0 投票
1 回答
877 浏览
提问于 2025-04-15 12:01

我有一个程序,可以通过火线设备(FA-66)录音,使用的是Jack连接。这个程序的界面是用pygtk做的,录音则是用py-jack来实现的(可以在这里找到:http://sourceforge.net/projects/py-jack/)。录音是在一个单独的线程中进行的,因为我需要同时使用图形界面来查看音频的录制结果。

问题是,当我启动录音线程时,图形界面的反应变得非常慢。我在主线程的开头调用了gtk.gdk的start_threads()函数。如果我理解得没错,我不需要使用threads_enter()和threads_leave(),因为录音并不会影响到图形界面。如果我错了,请纠正我。

jack.process()这个函数是用来从三个麦克风录音的。如果我把它换成比如time.sleep(2),那么一切就正常了。

在这种情况下,创建线程的最佳方式是什么呢?为什么jack.process会让图形界面卡住?它是不是占用了所有的CPU时间?下面是我代码的一些示例:

soundrecorder.py:

...
def start(self):
    Thread(target=self._start).start()

def _start(self):
    while self.eventhandler.record.isSet():
        data = self._jackRecord(self.sample_length)
        self.datahandler.queue.put(data)

def _jackRecord(self, length):
    capture = Numeric.zeros((self.inputs, int(self.sample_rate * length)), 'f')
    output = Numeric.zeros((self.inputs, self.buffer_size), 'f')
    i = 0
    while i < capture.shape[1] - self.buffer_size:
        try:
            jack.process(output, capture[:,i:i+self.buffer_size])
            i += self.buffer_size
        except:
            pass
    return capture        

eventhandler.py: recordStart()和recordStop()只是简单的回调函数,当按下开始和停止按钮时会被调用。

...
def recordStart(self, widget, data=None):
    if not self.record.isSet():
        self.record.set()
        self.soundrecorder = SoundRecorder(self, self.datahandler)
        self.soundrecorder.connect()
        self.soundrecorder.start()
def recordStop(self, widget, data=None):
    if self.record.isSet():
       self.record.clear()
       del(self.soundrecorder)

1 个回答

2

你对线程的工作原理有些误解。

在这种情况下,线程并不能帮你。

"当一个样本被记录时,它会被分析,结果会在图形界面上显示。同时,下一个样本已经在录制中。"

错了。线程并不能同时做两件事。在Python中,有一个全局锁,防止两个线程同时运行Python代码或操作Python对象。而且,如果你没有两个CPU或核心,实际上也不会有两件事同时发生。线程机制只是让它们在执行时切换,每次执行固定数量的指令。

使用线程还会增加处理、内存和代码的复杂性,但没有任何好处。使用线程的Python代码运行得更慢,性能也更低,比起单线程来说。只有少数情况例外,而你的情况并不在其中。

你可能想把你的录制循环改写成一个回调,并将其与GTK循环整合(这样性能会比使用线程更好)。

为此,可以使用一个优先级较高的gobject.idle_add

如果你想真正做到“两件事同时进行”,也就是使用两个处理器/核心,你需要启动另一个进程。启动一个进程来收集数据,并通过某种进程间通信机制将数据传输到另一个进程,这个进程负责分析和绘制数据。multiprocessing模块可以帮助你实现这一点。

撰写回答