Насколько быстр Flutter? Я создал программу секундомера, чтобы узнать.

1656656655 naskolko bystr flutter ya sozdal programmu sekundomera chtoby uznat

Андреа Биззотто

1*270WC2lY8lFF6jfPpca0WQ
Автор изображения: Петар Петковски

В эти выходные мне пора было поиграть с новой системой интерфейса Flutter от Google.

На бумаге звучит здорово!

Согласно документам, следует ожидать высокой производительности:

Flutter разработан, чтобы помочь разработчикам легко добиться постоянных 60 кадров в секунду.

Но как насчет использования ЦБ?

TL; DR: Не такой хороший, как родной И делать это нужно правильно:

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

Я создал простую программу секундомера во Flutter и профилировал ее для анализа использования процессора и памяти.

1*Bo0l0BjIRcInHZo2ACvjsA
Слева: Секундомер для iOS Верно: Моя версия у Flutter. Красиво, не правда ли?

Реализация

Пользовательский интерфейс управляется двумя объектами: секундомером и таймером.

  • Пользователь может запускать, останавливать и сбрасывать секундомер, нажав две кнопки.
  • Каждый раз, когда запускается секундомер, создается периодический таймер с обратным вызовом, который запускается каждые 30 мс и обновляет пользовательский интерфейс.

Основной UI построен так:

Как это работает?

  • Две кнопки управляют состоянием объекта секундомера.
  • Когда секундомер обновляется, setState() вызывается, запуская build() метод.
  • В составе build() метод, новый TimerText создается.

The TimerText класс выглядит так:

Пара примечаний:

  • Таймер создается вместе с TimerTextState объект. Каждый раз, когда срабатывает обратный вызов, setState() это называется если работает секундомер.
  • Это вызывает build() вызванный метод, рисующий новый Text объект с обновленным временем.

Делать это правильно

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

Это означало, что каждый раз, когда запускался обратный вызов таймера, весь пользовательский интерфейс перестраивался. Это излишне и неэффективно: только Text объект, содержащий прошедшее время, следует перерисовать — особенно потому, что таймер срабатывает каждые 30 мс.

Это становится очевидным, если мы рассмотрим неоптимизированную и оптимизированную иерархию виджетов:

1*YrJV5E7jWzr3K0kjPBs1Mg

Создание отдельного TimerText класс для инкапсуляции логики таймера менее интенсивным для ЦП.

Иными словами:

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

В документах Flutter отмечено, что платформа оптимизирована для быстрого распределения:

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

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

Обновление 19–03–2018

После публикации этой статьи некоторые инженеры Google обратили на это внимание и любезно внесли дополнительные оптимизации.

Обновленный код еще больше уменьшает перерисовку пользовательского интерфейса путем разделения TimerText на двоих MinutesAndSeconds и Hundredths виджеты:

1*NQxSNVJDSnZnC3DohLBTAA
Дальнейшая оптимизация пользовательского интерфейса (авторство: Google)

Они регистрируются как слушатели обратного вызова таймера и перерисовываются, только когда их состояние меняется. Это дополнительно оптимизирует производительность как только Hundredths виджет теперь рендерится каждые 30 мс.

Результаты бенчмаркинга

Я запустил программу в режиме выпуска (flutter run --release):

  • устройство: iPhone 6 бег iOS 11.2
  • Версия Flutter: 0.1.5 (22 февраля 2018 г.).
  • Xcode 9.2

Я наблюдал за использованием ЦП и памяти в Xcode в течение трех минут и измерял производительность трех разных режимов.

Не оптимизированный код

  • Использование ЦБ: 28%
  • Использование памяти: 32 МБ (от базового уровня 17 МБ после запуска программы)
1*F1GR6mVtVEwRjaJptEuEwQ

Проход оптимизации 1 (отдельный текстовый виджет таймера)

  • Использование ЦБ: 25%
  • Использование памяти: 25 МБ (от базового уровня 17 МБ после запуска программы)
1*dTO3vThMfGx0LYrLqAIlAQ

Проход оптимизации 2 (отдельные минуты, секунды, сотые)

  • Использование ЦБ: от 15% до 25%
  • Использование памяти: 26 МБ (от базового уровня 17 МБ после запуска программы)
1*JFnMDRT8utbB9C4ETPklOg

В этом последнем тесте график использования ЦБ точно отслеживает поток GPU, в то время как поток пользовательского интерфейса остается достаточно постоянным.

ПРИМЕЧАНИЕ: запуск того же теста медленный режим обеспечивает использование ЦБ более 50%, и использование памяти постоянно растет некоторое время спустя.

Это может указывать на то, что память не освобождается в режиме разработки.

Ключевой вывод: убедитесь, что профиль ваших программ в режиме выпуска.

Обратите внимание, что Xcode сообщает a очень высоко энергетическое влияние, когда использование ЦБ превышает 20%.

Копать глубже

Результаты заставили меня задуматься. Таймер, срабатывающий примерно 30 раз в секунду и повторно воспроизводящий текстовую метку, не должен использовать до 25% двухъядерного ЦБ 1,4 ГГц.

Дерево виджетов в Flutter построено с помощью a декларативная парадигмаа не императив модель программирования, используемая в iOS/Android.

Но эффективнее ли императивная модель?

Чтобы узнать это, я создал ту же программу секундомера на iOS.

Это код Swift для настройки таймера и обновления текстовой метки каждые 30 мс:

Для полноты вот код форматирования времени, которое я использовал в Dart (проход оптимизации 1):

Окончательные результаты?

трепет. ЦБ: 25%, память: 22 Мб

iOS. ЦБ: 7%, память: 8 Мб

Реализация Flutter более чем в 3 раза тяжелее для ЦБ и использует в 3 раза больше памяти.

Когда таймер не работает, использование ЦБ возвращается до 1%. Это подтверждает, что вся работа ЦП направлена ​​на обработку обратных вызовов таймера и перерисовку пользовательского интерфейса.

Это не совсем удивительно.

  • В приложении Flutter я строю и рендер новый Text виджет каждый раз.
  • В iOS я просто обновляю текст a UILabel.

«Эй!» – Я слышу, как вы говорите. «Но код форматирования времени другой! Как вы знаете, что разница в использовании процессора не связана с этим?

Тогда давайте модифицируем оба примера, чтобы вообще не форматировать:

Swift:

Дартс:

Обновленные результаты:

трепет. ЦБ: 15%, память: 22 Мб

iOS. ЦБ: 8%, память: 8 Мб

Реализация Flutter все еще вдвое более интенсивна для ЦБ. Кроме того, кажется, что он выполняет достаточно много вещей в нескольких потоках (графический процессор, работа ввода/вывода). В iOS активен только один поток.

Вывод

Я сравнил производительность Flutter/Dart с iOS/Swift в очень конкретном случае использования.

Цифры не врут. Что касается частых обновлений пользовательского интерфейса, Вы не можете получить свой торт и съесть его тоже. ?

Flutter позволяет разработчикам создавать приложения для iOS и Android с одинаковой кодовой базой. А такие функции как горячая перезагрузка еще больше повышают производительность. Flutter все еще на зародыше. Я надеюсь, что Google и сообщество смогут улучшить профиль выполнения, чтобы эти преимущества были переданы конечным пользователям.

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

Я добавил весь код для этого проекта в это хранилище GitHub, так что вы можете поиграть с ним самостоятельно.

Добро пожаловать! ?

Этот пример проекта был моим первым экспериментом с Flutter. Если вы знаете, как написать более производительный код, я хотел бы услышать ваши комментарии.

1*TZ8Z0EnBGBugOs8mh19mHA

Обо мне: Я разработчик iOS и Flutter, жонглирую между работой по контракту, открытым кодом, сторонними проектами и ведением блогов.

Я @biz84 в Twitter. Вы также можете просмотреть мою страницу GitHub. Отзывы, твиты, смешные гифки, приветствуются! Мой любимый? Многие???. Ну и банановый хлеб.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *