Почему GetMessageW будет сильно загружать процессор в моем приложении WPF?

StackOverflow https://stackoverflow.com/questions/4127625

Вопрос

У меня тут серьезная головная боль.Я изучаю проблемы с производительностью компонента WPF в нашем приложении.

Наше .net-приложение очень большое и почти полностью выполнено в форме Windows.В рамках новой инициативы мы переписали один из наших основных компонентов, добавив богатый пользовательский интерфейс WPF.С этой штукой происходит много взаимодействия WinForms<-->WPF, и я подозреваю, что это может быть каким-то образом связано с тем, что я вижу.

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

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

Наш компонент WPF, о котором идет речь, наследуется от Window (т.это не просто элемент управления/пользовательский элемент управления), и мы показываем это с помощью ShowDialog из нашей логики более высокого уровня, которая раньше вызывала ShowDialog в старой версии WinForms этого компонента.Внутри компонента WPF мы использовали некоторые элементы управления WindowsFormsIntegrationHost, чтобы сохранить совместимость с некоторыми из наших существующих частей, которые невозможно переписать в WPF.

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

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

Вот изображение графа вызовов ANTS функции ShowDialog, показывающее путь вызовов сюда:alt text

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

ОБНОВЛЯТЬ:В ответ на некоторые обсуждения ниже, вот еще один вид от ANTS - он лучше иллюстрирует мою путаницу (это представление ANTS в режиме «ЦП»).Я поспешно подверг цензуре части нашего кода, но ни одну из функций, связанных с системой:

alt text

Спасибо за поиск!

Это было полезно?

Решение

Я нашел это при поиске информации по одной и той же проблеме. Я добавлю то, что знаю, и посмотрю, поможет ли это:

Я работаю на Winxp Box - фреймворк WPF более интегрирована в Vista и Win7, чем в XP. Отчасти это может быть связано с тем, как WPF работает «сверху» на рабочем столе XP, а не в нем.

Я запускаю чистого нативного приложения WPF - без Winforms или другого кода.

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

Управляя AQTime Performance Profiler, я вижу, что IntgetMessagew занимает самую большую часть этого 100% использования процессора. Это не из -за того, что IntgetMessagew ожидает сообщения, а то, что на самом деле выполняет функция.

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

Другие советы

Да, это нормально. Любое приложение GUI всегда Выполнение getMessagew (), ожидая, пока Windows отправит ему сообщение. На самом деле он не сжигает циклы процессора, выполняющие это, просто заблокировано на внутреннем объекте синхронизации, пока не будет сигнализируется какое -то событие пользовательского интерфейса.

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

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

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

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

Я предлагаю вам также потратить некоторое время изучение возможностей профайлера быть максимально эффективным. Профилировщики могут оказаться сложными и запутанными инструментами, пока вы не поймете, что они пытаются вам показать.Связанное руководство от RedGate должно быть хорошим началом, если вы еще этого не сделали.Например, представление «Временная шкала» на самом деле может быть хорошим местом, чтобы начать видеть, где происходит высокая активность ЦП, и ограничить ваш анализ этими сегментами исполняемого кода.

alt text

Граф вызовов — еще один полезный инструмент в ANTS, поскольку он помогает детализировать наиболее затратные области кода.Главное — убедиться, что вы смотрите на общая стоимость и не только общее время.

alt text

Похоже, ваш насос сообщения много накачивает. Может быть интересно посмотреть, какое сообщение заполнено ваша очередь сообщения. Можете ли вы использовать Spy ++ в своем окне, чтобы увидеть, что происходит?

Редактировать

Я неправильно понял проблему.

Hans Passant прав, ваша программа просто ждет GetMessage для какого -то события для обработки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top