Поддержание отзывчивости GUI во время длительных задач - PullRequest
11 голосов
/ 29 сентября 2008

Поддержание адаптивности графического интерфейса пользователя, пока приложение выполняет некоторую нагрузку на процессор, - одна из задач эффективного программирования GUI.

Вот хорошее обсуждение того, как это сделать в wxPython. Подводя итог, есть 3 способа:

  1. Использовать темы
  2. Использовать wxYield
  3. Разделите работу на части и сделайте это в обработчике событий IDLE

Какой метод вы считаете наиболее эффективным? Также приветствуются методы из других сред (например, Qt, GTK или Windows API).

Ответы [ 9 ]

15 голосов
/ 29 сентября 2008

Темы. Они - то, к чему я всегда стремлюсь, потому что вы можете делать это в любых рамках, которые вам нужны.

И как только вы привыкли к многопоточности и параллельной обработке на одном языке / фреймворке, у вас все хорошо.

7 голосов
/ 29 сентября 2008

Определенно темы. Зачем? Будущее многоядерное. Почти любой новый ЦП имеет более одного ядра или, если он имеет только одно, он может поддерживать гиперпоточность и, таким образом, притворяться, что у него более одного. Чтобы эффективно использовать многоядерные процессоры (а в ближайшем будущем Intel планирует использовать до 32 ядер), вам нужно несколько потоков. Если вы запускаете все в одном основном потоке (обычно поток пользовательского интерфейса является основным потоком), у пользователей будут центральные процессоры с 8, 16 и однодневными 32 ядрами, и ваше приложение никогда не использует более одного из них, поэтому оно работает намного, намного медленнее. чем он мог бежать.

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

На самом деле такие компании, как Apple и Microsoft, уже планируют, как сделать свои однопоточные интерфейсы сами по себе многопоточными. Даже с подходом, описанным выше, однажды вы можете столкнуться с тем, что интерфейс является узким местом. Фоновые процессы могут обрабатывать данные намного быстрее, чем пользовательский интерфейс может представить их пользователю или запросить ввод данных. Сегодня многие фреймворки пользовательского интерфейса мало поточнобезопасны, многие вообще не поточнобезопасны, но это изменится. Последовательная обработка (выполнение одной задачи за другой) - умирающий дизайн, параллельная обработка (выполнение множества задач одновременно) - это то, куда уходит будущее. Просто посмотрите на графические адаптеры. Даже самая современная карта NVidia имеет жалкую производительность, если вы посмотрите на скорость обработки в МГц / ГГц одного GPU. Как получается, что он может выбить дерьмо из процессоров, когда дело доходит до 3D вычислений? Просто: вместо того, чтобы вычислять одну точку многоугольника или один пиксель текстуры за другим, он вычисляет многие из них параллельно (фактически целую кучу одновременно) и таким образом достигает пропускной способности, которая все еще заставляет процессоры плакать. Например. ATI X1900 (на имя конкурента) имеет 48 шейдерных блоков!

2 голосов
/ 18 декабря 2008

Я думаю delayedresult - это то, что вы ищете:

http://www.wxpython.org/docs/api/wx.lib.delayedresult-module.html

См. Пример демоверсии wxpython.

1 голос
/ 29 сентября 2008

Темы - Давайте использовать простое двухслойное представление (GUI, логика приложения).

Работа логики приложения должна выполняться в отдельном потоке Python. Для асинхронных событий, которые необходимо распространять до уровня графического интерфейса, используйте систему событий wx для публикации пользовательских событий. Публикация событий wx является поточно-ориентированной, так что вы можете сделать это из разных контекстов.

Работая в другом направлении (входные события GUI запускают логику приложения), я считаю, что лучше всего прокрутить систему пользовательских событий. Используйте модуль Queue, чтобы иметь потокобезопасный способ проталкивания и извлечения объектов событий. Затем для каждой синхронной функции-члена свяжите ее с асинхронной версией, которая помещает объект функции синхронизации и параметры в очередь событий.

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

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

edit - Забыл упомянуть, что прелесть заключается в том, что можно полностью отделить логику приложения от кода GUI. Модульность помогает, если вы когда-нибудь решите использовать другую среду или предоставите версию приложения для командной строки. Для этого вам понадобится диспетчер промежуточных событий (уровень приложения -> GUI), который реализован на уровне GUI.

1 голос
/ 29 сентября 2008

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

0 голосов
/ 29 сентября 2008

Для некоторых типов операций использование отдельных процессов имеет большой смысл. В свое время порождение процесса повлекло за собой много накладных расходов. С современными аппаратными средствами эти издержки вряд ли даже всплывают на экране. Это особенно верно, если вы запускаете длительный процесс.

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

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

0 голосов
/ 29 сентября 2008

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

0 голосов
/ 29 сентября 2008

Этот ответ не относится к вопросу ОП относительно Python, но является скорее мета-ответом.

Простой способ - это темы. Тем не менее, не каждая платформа имеет преимущественную многопоточность (например, BREW, некоторые другие встроенные системы) Если возможно, просто разделите работу на части и сделайте это в обработчике событий IDLE.

Другая проблема с использованием потоков в BREW заключается в том, что он не очищает объекты стека C ++, поэтому утечка памяти становится слишком простой, если вы просто уничтожаете поток.

0 голосов
/ 29 сентября 2008

Работа с Qt / C ++ для Win32.

Мы разделяем основные рабочие блоки на разные процессы. Графический интерфейс запускается как отдельный процесс и может при необходимости командовать / получать данные от «рабочих» процессов. Прекрасно работает в современном многоядерном мире.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...