PyGTK GUI зависает с нитью PyJack - PullRequest
0 голосов
/ 03 июня 2009

У меня есть программа, которая записывает звук с устройства FireWire (FA-66) с разъемом Jack. Интерфейс создается с помощью pygtk, а запись - с помощью py-jack (http://sourceforge.net/projects/py-jack/).. Запись выполняется в другом потоке, поскольку графический интерфейс пользователя должен использоваться одновременно для просмотра результатов аудио.

Проблема в том, что когда я запускаю поток записи, графический интерфейс очень медленно реагирует. У меня есть функция gtk.gdk start_threads () в начале основного потока. Если я правильно понял, мне не нужны threads_enter () и threads_leave (), потому что запись не влияет на GUI. Пожалуйста, исправьте, если я ошибаюсь.

Функция jack.process () записывает звук с трех микрофонов. Если я заменю его, например, на time.sleep (2), все будет нормально.

Каков наилучший способ создания потоков в этом случае? Почему jack.process зависает в графическом интерфейсе? Это займет все время процессора или что-то? Образцы моего кода ниже:

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 голосов
/ 03 июня 2009

Вы неправильно понимаете, как работают потоки.

Темы не помогут вам в этом случае.

"Тогда, когда один образец записан, он будет проанализирован, и результаты показано в графическом интерфейсе. В то же время следующий образец уже записано ".

НЕВЕРНО . Потоки не делают две вещи одновременно. В python есть глобальная блокировка, которая не позволяет двум потокам одновременно запускать код python или касаться объектов python. И, кроме того, две вещи никогда не происходят одновременно, если у вас нет двух процессоров или ядер. Механизм потоков просто переключается между ними, выполняя фиксированное количество инструкций для каждого за раз.

Потоки также добавляют накладные расходы на обработку, память и сложность кода для бесполезно . Код Python, использующий потоки, работает на медленнее и имеет меньшую производительность , чем если бы он был однопоточным. Из этого правила есть только несколько исключений, и ваш случай не является одним из них.

Возможно, вы захотите переписать ваш цикл записи как обратный вызов и интегрировать его с циклом GTK (вы получите более высокую производительность, чем при использовании потоков).

Для этого используйте gobject.idle_add с большим приоритетом.

Если вы хотите запустить две вещи действительно «одновременно», используя два процессора / ядра, вы хотите запустить другой процесс. Запустите процесс для сбора данных и передачи их через некоторый механизм межпроцессного взаимодействия другому процессу, который анализирует и выводит данные на график. многопроцессорный модуль может помочь вам в этом.

...