2009-06-03 2 views
0

Ich habe ein Programm, das Audio von Firewire-Gerät (FA-66) mit Jack-Verbindung aufzeichnet. Die Schnittstelle wird mit pygtk und der Aufnahme mit py-jack (http://sourceforge.net/projects/py-jack/) erstellt. Die Aufzeichnung erfolgt in einem anderen Thread, da die GUI gleichzeitig zum Anzeigen von Ergebnissen aus dem Audio verwendet werden muss.pygtk gui friert mit Pyjack Thread

Das Problem ist, dass die GUI sehr langsam reagiert, wenn ich den Aufnahme-Thread starte. Ich habe gtk.gdk Funktion start_threads() am Anfang des Hauptthreads. Wenn ich es richtig verstanden habe, brauche ich weder threads_enter() noch threads_leave(), da sich die Aufzeichnung nicht auf die GUI auswirkt. Bitte korrigieren Sie, wenn ich falsch liege.

Die Funktion jack.process() nimmt Audio von drei Mikrofonen auf. Wenn ich es zum Beispiel mit time.sleep (2) ersetze, funktioniert alles ok.

Was ist der beste Weg, um Threading in diesem Fall zu erstellen? Warum friert der jack.process die GUI ein? Benötigt es die ganze CPU-Zeit oder so? Proben von meinem Code unten:

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() und recordStop() einfach Callback-Funktionen, die aufgerufen werden, wenn Start- und Tasten gedrückt werden aufhören.

... 
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) 
+0

"Die Aufnahme erfolgt in einem anderen Thread, da die GUI gleichzeitig zum Anzeigen von Ergebnissen aus dem Audio verwendet werden muss" - Das ist falsch. Kein Grund, Threads zu verwenden. Sie sollten Threads nur verwenden, wenn die Aufzeichnungs-API blockiert. Ansonsten kannst du beides im selben Thread (besser) machen. – nosklo

+0

Vielleicht habe ich es nicht richtig erklärt. Die Aufnahme erfolgt in einer Schleife, so dass es keine Pausen gibt oder sie so minimal wie möglich sind. Wenn dann ein Sample aufgenommen wird, wird es analysiert und die Ergebnisse werden in der GUI angezeigt. Zur gleichen Zeit wird bereits das nächste Sample aufgenommen. Wenn es nicht gut ist, Threads zu verwenden, habe ich keine Ahnung, wie das gemacht werden muss. –

Antwort

2

Sie missverstehen, wie Threads funktionieren.

Threads helfen Ihnen in diesem Fall nicht.

„dann, wenn eine Probe aufgezeichnet wird, wird es analysiert und die Ergebnisse sind in dem GUI gezeigt. Zur gleichen Zeit die nächste Probe wird bereits aufgezeichnet.“

FALSCH. Threads machen nicht zwei Dinge gleichzeitig. In Python gibt es eine globale Sperre, die verhindert, dass zwei Threads Python-Code ausführen oder Python-Objekte gleichzeitig berühren. Und außerdem passieren zwei Dinge niemals zur gleichen Zeit, wenn Sie nicht zwei CPUs oder Kerne haben. Der Threading-Mechanismus schaltet einfach zwischen ihnen um und führt jeweils eine feste Anzahl von Anweisungen aus.

Threads fügen auch einen Verarbeitungs-, Speicher- und Codekompatibilitäts-Overhead für hinzu, kein Vorteil. Python-Code mit Threads ausführen langsamer und haben niedrigere Leistung als wenn es single-threaded wäre. Es gibt nur wenige Ausnahmen für diese Regel und Ihr Fall gehört nicht dazu.

Sie möchten Ihre Aufnahmeschleife wahrscheinlich als Callback umschreiben und in die GTK-Schleife integrieren (Sie erhalten eine bessere Leistung als die Verwendung von Threads).

Dafür verwenden Sie eine gobject.idle_add mit einer großen Priorität.

Wenn Sie mit zwei Prozessoren/Kernen gleichzeitig zwei Dinge zur gleichen Zeit ausführen möchten, möchten Sie einen anderen Prozess starten. Starten Sie einen Prozess, um Daten zu sammeln und über einen prozessübergreifenden Kommunikationsmechanismus an den anderen Prozess zu übertragen, der Daten analysiert und grafisch darstellt. multiprocessing Modul kann Ihnen dabei helfen.

+0

Danke für Ihre Antwort. Ich bin mir der Tatsache bewusst, dass Dinge in Threads nicht genau zur gleichen Zeit passieren, es sei denn, ich habe zwei CPUs. Ich wusste einfach nicht anders. Ich werde diese gobject.idle_all-Methode ausprobieren. –

+0

@jushie: selbst mit zwei CPUs sind Sie durch die globale Interpretersperre Python eingeschränkt. Threads sind dafür einfach nicht geeignet. Verwenden Sie entweder den Ansatz mit einem einzelnen Thread (gobject.idle_add, gobject.timeout_add, gobject.io_add_watch, oder verwenden Sie twisted) oder den Multiprozess-Ansatz. – nosklo