2008-09-29 2 views
11

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

Here's a good discussion Как это сделать в wxPython. Подводя итог, есть 3 способа:

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

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

ответ

15

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

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

+0

За исключением каркасов, которые не имеют реальной резьбы (BREW). –

0

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

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

1

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

0

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

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

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

0

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

0

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

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

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

+0

Каким образом процессы проще концептуально, чем потоки? Обмен данными между потоками намного проще, чем между процессами, например. –

+0

И именно поэтому процессы проще; нет общих данных. Правильное выполнение резьбового программирования (блокировка, избегание условий гонки и т. Д.) - это трудная проблема, и если вы считаете, что это просто, вы делаете это неправильно. –

+0

Ну, если у вас нет общих данных, проблем с потоками тоже нет. Но иногда у вас должны быть общие данные, и с процессами трудно добиться эффективного. –

7

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

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

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

+0

Мой мобильный телефон не является многоядерным, и это, вероятно, не будет на некоторое время. – tloach

1

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

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

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

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

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

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

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