Pull to refresh

Производительность таблиц в WPF и Avalonia

Level of difficultyMedium
Reading time3 min
Views3.4K

Предыстория: как-то возникла у меня необходимость в приложении на WPF сделать таблицу с количеством столбцов в несколько десятков, притом с шаблонизированным содержимым. По задумке пользователь должен иметь возможность выбрать столбцы, которые нужны, но по умолчанию должны быть видны все. Решение не то чтобы сложное, но после сборки и запуска оно начало жутко тормозить... Проведённое по-быстрому исследование показало, что тупит этап layout-а, но в моменте было принято решение вбить костыль и преобразовать представление до удобоваримого. Однако червячок остался и поисследовать поведение хотелось более детально, а заодно сравнить с другими элементами для отрисовки таблиц.

Результатом такого исследования и стала данная статья. Полученные результаты - под катом.

Тестовое приложение
Тестовое приложение

Тестовый стенд - не самая свежая машинка:

  • CPU Intel Core i7-6700K 4 GHz (4 ядра, 8 потоков)

  • DDR4 32GB 2133 MHz, двумя планками

  • GPU NVidia GeForce GTX 1080, к которой подключены мониторы (1) и (3)

  • GPU Intel HD Graphics 530, подключен монитор (2)

  • Мониторы:

    • 1680х1050

    • 1920х1080 в портретной ориентации

    • 3840х2160 с масштабным фактором 1.5

Windows 10, .NET 7

Для начала я сгенерировал некоторую модель представления, в которой есть 64 столбца данных и 1000 строк. Данные - это числа от 0 до 1, и дополнительные атрибуты, которые вычисляются в зависимости от значения: до 0.2 - ниже нормы, более 0.8 - выше нормы. Значения заполняются рандомом.

Тестовый проект доступен в репозитории на Гитхабе.

WPF

Для WPF сгенерировано некоторое количество вкладок с таблицами с разным количеством столбцов, которые либо DataGridTextColumn, либо собственный DataGridObjectColumn, сделанный на основе DataGridTextColumn с небольшой переделкой создаваемого TextBlock-а на ContentControl.

Измерение производилось путём замера времени между событиями SelectionChanged (момент запроса перерисовки) и LayoutUpdated (завершение перерисовки) для TabControl-а, в котором размещались тестируемые компоненты.

На вычисление размера влияет также размер экрана. Соответственно я разворачивал окно на каждое из них и запускал автоматический прогон по 10 раз для каждого шаблона поочерёдно и собирал статистику. Кроме того, я проводил измерения в окне размером 850х400 пикселей на первом и последнем мониторе. Сильнее всего тормоза были на портретном мониторе (вероятно, дело в более слабой карте, к которой он подключен, но это не точно).

Итак, табличка и картинка:

Данные, время в миллисекундах
Данные, время в миллисекундах

Вывод: время лэйаута - линейное относительно количества столбцов.

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

Данные, время в миллисекундах
Данные, время в миллисекундах

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

AvaloniaUI

Для Авалонии был сделан идентичный проект с учётом несколько отличающейся системы стилей.

Данные, время всё так же в миллисекундах
Данные, время всё так же в миллисекундах

Общий вывод: Авалония значительно шустрее рисует таблицы, от количества столбцов зависит слабо, от шаблонизации зависит слабо. Но свёрнутое окно рисуется ощутимо быстрее развёрнутого.

Но пойдём дальше. Разработчики рекомендуют использовать TreeDataGrid вместо DataGrid по соображениям производительности. Что ж, попробуем.

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

Данные, время в миллисекундах
Данные, время в миллисекундах

Как видим, важно количество видимых на экране столбцов, но не общее количество и площадь окна. На вертикально ориентированном мониторе тормозит сильнее.

Вывод: Авалония работает с табличными данными быстрее и плавнее, однако местами есть трудности с гибкостью самого фреймворка...

Бонус: Avalonia+NativeAOT

После обсуждения в уютном телеграмном чатике AvaloniaUI (RU) для TreeDataGrid проект адаптирован под NativeAOT и измерен вклад... И он примерно отсутствует. Вероятно, после прогрева разница нивелируется. Но цифры и графики всё равно приведу:

Времена как и раньше в миллисекундах
Времена как и раньше в миллисекундах

Tags:
Hubs:
Total votes 13: ↑13 and ↓0+13
Comments6

Articles