2014-02-19 5 views
0

У меня есть странная проблема. У меня есть двухпроцессорная аппликация, написанная на python и PySide для графического интерфейса.Пользовательский интерфейс Python не реагирует после долгого запуска

GUI запускается в первом потоке и разворачивает второй процесс (для предотвращения использования Python GIL), в котором запущена система измерения-statemachine. После запуска этот FSM отправляет сообщения через сокет в хост-приложение (для связи). Это время выполнения FSM часто очень длинное (5 часов).

Проблема в том, что каким-то образом приложение-хост становится невосприимчивым. Пользовательский интерфейс больше не обновляется (полученные сообщения от второго процесса больше не отображаются), а Windows говорит, что приложение не отвечает. Второй процесс все еще работает правильно.

Может ли кто-нибудь помочь мне отладить это? Это происходит только для очень длинных FSM и когда в FSM многое предстоит сделать. Может ли это быть общей проблемой ressource?

Редактировать: Код ниже firs t показывает метод выполнения потока, захватывающий сообщения от вторых процессов. Это вызывает обратный вызов, который определен ниже. Этот обратный вызов только испускает сигналы (и подает их с полученными данными) для обновления пользовательского интерфейса (например, для входа в пользовательский интерфейс).

class RunnerServer(QThread): 
    # ... 
    def run(self): 
     try: 
      self._socket.bind((self._host, 0)) 
      self._port = self._socket.getsockname()[1] 
      self._is_started.set() 
      while not self._stop_event.is_set(): 
       try: 
        data = self._socket.recvfrom(2048)[0] 
       except socket.error : 
        continue 
       if self._callback: 
        o = pickle.loads(data) 
        self._callback(o, *self._args, **self._kwargs) 
     except: 
      traceback.print_exc() 
     finally: 
      self._socket.close() 


class Controller: 
    # ... 
    def remote_server_rx_callback(self, message, *args, **kwargs): 
     if isinstance(message, RunnerMessage): 
      self._sig_log_msg.emit(lmessage.message_type, message.message, message.source 
     elif isinstance(message, StatusMessage): 
      if message.message_type == StatusType.START: 
       self._sig_runner_started.emit() 
      elif message.message_type == StatusType.FINISH: 
       self._sig_runner_finished.emit() 
      elif message.message_type == StatusType.PROGRESS: 
       self._sig_runner_update_progress.emit(message.payload['progress']) 
+0

Не могли бы вы привести пример кода, который поможет вам выявить проблему? Иногда многопоточность с графическим интерфейсом сложна. –

+0

@xndrme Я добавил некоторые фрагменты кода. – Razer

+0

не видит ничего плохого в потоке против сигналов. Это происходит после того, как много сообщений журнала? Если вы удалите код, который запускает процесс, и замените материал сокета кодом, который снова и снова выдает одно и то же текстовое сообщение, вы видите одно и то же замедление? Сколько сообщений? – Schollii

ответ

0

Я нашел узкое место. Это неторопливая связь сокетов и отсутствие сигналов. Связанные слоты печатают это в текстовое поле, используя QTextEdit.insertHtml(msg). Этот вызов метода неприменим для неответственности.

Теперь я попытаюсь удалить этот вид и добавить вместо него TableView. Затем сообщения добавляются к прикрепленной модели. Надеюсь, это сработает лучше - или есть ли лучшие подходы?

0

Обычно я решить такого рода проблемы путем вызова QtGui.qApp.processEvents() внутри работающей петли.

Например, если у меня есть for цикл обработки много информации (что иногда делает окно не отвечает), я вызываю QtGui.qApp.processEvents() в конце цикла. Этот вызов заставляет графический интерфейс реагировать, обрабатывая все события. Другими словами, это обновит окно.

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

+0

Основной пользовательский интерфейс довольно асинхронный. В потоке пользовательского интерфейса на самом деле нет такого ** длительного метода **. В хост-процессе есть второй поток, который передает принятые сообщения, а затем излучает сигналы для обновления пользовательского интерфейса. Пользовательский интерфейс не перестает реагировать. Это больше, когда FSM работает дольше. Похоже, что по какой-то причине основной процесс больше не получает никаких ресурсов. Поскольку поток пользовательского интерфейса асинхронный, я думаю, что нет места для размещения 'processEvents()'. Вызывать это из сокетной нити, думаю, невозможно/полезно? – Razer

0

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

+0

Вы правы. В хост-процессе есть один SocketReceiveThread. Это испускает QT-сигналы для выполнения некоторой UI-магии. (например, записать полученное сообщение журнала в пользовательский интерфейс) – Razer

+0

Итак, SocketReceiveThread использует только сигналы, напрямую не использует какой-либо метод пользовательского интерфейса? Позаботьтесь, чтобы показать эту часть вашего кода в своем вопросе? – Schollii

+0

Я обновил свой вопрос с помощью некоторых фрагментов кода. – Razer

Смежные вопросы