Буферизация диспетчерского интерфейса? - PullRequest
4 голосов
/ 28 апреля 2011

У меня есть загадка.Я «унаследовал» очень плохо спроектированную и очень сложную систему, которую я модернизирую и перестраиваю (со своей командой) по частям.Проблема в том, что текущая система зависит от 200+ пользователей, и у них есть серьезные проблемы с производительностью из-за (отсутствия) дизайна.Наиболее проблематичной проблемой на данный момент является то, что значительный объем работы выполняется в потоке пользовательского интерфейса, что приводит к зависанию графического интерфейса пользователя до тех пор, пока поток не будет очищен, а прокачка сообщений может продолжаться.Большая часть этой работы действительно должна выполняться в потоке графического интерфейса, поскольку он обновляет большое количество полей в сетке из-за других результатов вычислений в других потоках.

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

Я хотел бы знать, есть ли у кого-нибудь предложения о том, как сделать пользовательский интерфейс более производительным, не слишком сильно мешая модели потоков в currnet.

Сначала я подумал, что может быть какой-то способпоместить «буфер» перед фактическими вызовами потока UI, чтобы убедиться, что графический интерфейс не перегружен или когда он отменяет отправку к нему.

Любые предложения будут весьмаоценили.

Я знаю, что ничего из этого не является идеальным, но мы находимся там, где мы есть, и я действительно хочу дать своим пользователям лучший опыт до завершения годовой переписывания!

Спасибо!

Обновление # 1 Это приложение winforms ... извините, это не было ясно с самого начала.Новый код - WPF, но эти модули - winforms.

Update # 2 Я думаю, что я могу сначала попытаться изменить большинство вызовов BeginInvoke на поток пользовательского интерфейса на Invoke, вводя сериализацию, которая, будем надеяться,повысить отзывчивость интерфейса.Есть ли здесь (неочевидные) недостатки, которые кто-либо может предвидеть?

Ответы [ 3 ]

1 голос
/ 29 апреля 2011

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

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

Что касается производительности пользовательского интерфейса, иногда лучший способ сделать его быстрее - это делать меньше.Приложение, над которым я работал, когда создавал связанный код, анализировало сотни мегабайт строк, чтобы вручную обработать некоторые xml.Замена неизменяемых строк строителями строк взяла операцию от состояния отказа OOM до завершения в течение 5 минут времени настенных часов.Затем я заметил, что для каждого анализируемого элемента он обновляет интерфейс.Я настроил этот код для обновления пользовательского интерфейса каждые 50 элементов или около того, и это заняло всего несколько минут.Отключение всех обновлений пользовательского интерфейса сбило время до нескольких секунд.

Рассматривали ли вы обновление пользовательского интерфейса до завершения вычислений, возможно, вместо этого просто запустите индикатор выполнения?Еще одна возможность (вне моей головы, не знаю, насколько она злая) состояла бы в том, чтобы ставить обновления в очередь как лямбды в словаре, который отключен от обновляемого элемента управления.Таким образом, вы можете заменить избыточные обновления значений, если один элемент управления обновляется несколько раз, например (это предполагает, что приложение, конечно, не считывает значения непосредственно из пользовательского интерфейса для выполнения вычислений. Что, вероятно, так и есть. :()

0 голосов
/ 29 апреля 2011

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

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

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

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

0 голосов
/ 29 апреля 2011

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

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