2009-06-03 6 views
0

J'ai un programme qui enregistre l'audio du périphérique Firewire (FA-66) avec la connexion Jack. L'interface est créée avec pygtk et l'enregistrement avec py-jack (http://sourceforge.net/projects/py-jack/). L'enregistrement est effectué dans un thread différent car l'interface graphique doit être utilisée en même temps pour afficher les résultats de l'audio.pygtk gui gèle avec le fil de pyjack

Le problème est que lorsque je démarre le fil d'enregistrement, l'interface graphique devient très lente à répondre. J'ai la fonction gtk.gdk start_threads() au début du thread principal. Si je l'ai bien, je n'ai pas besoin de threads_enter() et de threads_leave(), car l'enregistrement n'affecte pas l'interface graphique. Veuillez corriger si j'ai tort.

La fonction jack.process() enregistre l'audio à partir de trois microphones. Si je le remplace, par exemple, avec time.sleep (2), tout fonctionne bien.

Quelle est la meilleure façon de créer du filetage dans ce cas? Pourquoi le jack.process gèle-t-il l'interface graphique? Est-ce que ça prend tout le temps du CPU ou quelque chose? Des échantillons de mon code ci-dessous:

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() et recordstop() sont des fonctions simplement rappel qui sont appelés lorsque le démarrage et boutons d'arrêt sont pressés.

... 
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

"L'enregistrement se fait dans un fil différent parce que l'interface graphique doit être utilisée en même temps pour afficher les résultats de l'audio" - C'est incorrect. Pas une raison d'utiliser des discussions. Vous devez utiliser des threads uniquement si l'API d'enregistrement bloque. Sinon, vous pouvez simplement faire les deux dans le même thread (mieux). – nosklo

+0

Peut-être que je ne l'ai pas expliqué correctement. L'enregistrement se fait en boucle afin qu'il n'y ait pas de pauses ou qu'elles soient aussi minimes que possible. Ensuite, lorsqu'un échantillon est enregistré, il sera analysé et les résultats sont affichés dans l'interface graphique. En même temps, l'échantillon suivant est déjà enregistré. Si ce n'est pas bon d'utiliser des threads, je n'ai aucune idée de comment cela doit être fait. –

Répondre

2

Vous ne comprenez pas le fonctionnement des unités d'exécution.

Les fils ne vous aident pas dans ce cas.

« Puis, quand un échantillon est enregistré, il sera analysé et les résultats sont montré dans l'interface graphique. En même temps, l'échantillon suivant est déjà enregistré. »

MAL. Les threads ne font pas deux choses en même temps. En python, il y a un verrou global qui empêche deux threads d'exécuter du code python ou de toucher des objets python en même temps. Et en plus de cela, deux choses ne se produisent jamais en même temps si vous n'avez pas deux processeurs ou noyaux. Le mécanisme d'enfilage bascule simplement entre eux en exécutant un nombre fixe d'instructions de chacun à la fois.

Les threads ajoutent également une surcharge de traitement, de mémoire et de code pour aucun avantage. Le code Python utilisant les threads exécute plus lent et a performances inférieures à que s'il s'agissait d'un seul thread. Il n'y a que quelques exceptions pour cette règle et votre cas n'en fait pas partie.

Vous souhaitez probablement réécrire votre boucle d'enregistrement en tant que rappel et l'intégrer à la boucle GTK (vous obtiendrez de meilleures performances que d'utiliser des threads).

Pour cela, utilisez un gobject.idle_add avec une grande priorité.

Si vous voulez exécuter deux choses en même temps, en utilisant deux processeurs/cœurs, vous voulez lancer un autre processus. Lancer un processus de collecte de données et le transmettre via un mécanisme de communication inter-processus à l'autre processus qui analyse et trace les données. multiprocessing module peut vous aider avec cela.

+0

Merci pour votre réponse. Je suis conscient du fait que les choses dans les threads ne se produisent pas exactement en même temps, sauf si j'ai deux processeurs. Je ne savais pas d'autre moyen de le faire. Je vais essayer cette méthode gobject.idle_all. –

+0

@jushie: même avec deux processeurs, vous êtes limité par le verrou d'interpréteur global python. Les threads ne sont tout simplement pas utiles pour ça. Choisissez une approche à un seul thread (gobject.idle_add, gobject.timeout_add, gobject.io_add_watch ou use twisted) ou l'approche multiprocessus. – nosklo