1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-Thread.md 12 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Объединение платформенного и UI потока в Flutter? Как это влияет?

С выпуском Flutter 3.29 был сделан «важный» шаг: начиная с версии 3.29, Flutter на Android и iOS будет выполнять Dart-код на главном потоке приложения, и больше не будет отдельного потока Dart UI

Может быть, некоторые люди еще не знакомы с этим понятием, поэтому стоит обратиться к ранее опубликованному материалу «Глубокое понимание механизма асинхронной реализации Dart», где рассматривается связь между isolate, thread и runner.

Кратко говоря:

  • Все Dart-код выполняется внутри какого-то isolate, например, наш входной метод main работает внутри корневого isolate, который является также основным потоком Dart-кода.
  • Отношение между isolate и потоками не всегда 1:1, но выполнение требует одного потока.
  • Runner — это абстрактное понятие в Flutter, которое не имеет прямой связи с isolate. На самом деле, движок Flutter не заботится о том, на каком потоке конкретный runner выполняется; он может отправлять задачи в runner, поэтому его также называют TaskRunner. Например, в Flutter есть четыре TaskRunner (UI, GPU, IO, Platform).

Схема потоков

На устройствах Android и iOS раньше создавались отдельные потоки для UI, GPU и IO, где UI Task Runner совпадал с корневым isolate Dart, то есть с основным потоком Dart-кода, а Platform Runner представлял собой главный поток платформы устройства.Поэтому в прошлом UI Runner и Platform Runner находились в разных потоках: Dart-корневой isolate был связан с UI Task Runner.

Из-за этого существовали асинхронные platform channels в Flutter, поскольку UI Runner и Platform Runner были разделены на разные потоки, что требовало сериализации и асинхронной передачи сообщений при взаимодействии Dart и Native.

Начиная с версии 3.29, как часть улучшений взаимодействия Native и Dart на мобильных платформах, два этих потока были объединены, другими словами, UI Runner = Platform Runner.

Объединённые потоки

Да, по умолчанию теперь merged_platform_ui_thread установлен в true, то есть UI Runner теперь равен Platform Runner, следовательно, Dart-корневой isolate связан с Platform Runner. Кроме того, раньше связывание корневого изолята Dart с UI Runner происходило при вызове SetMessageHandlingTaskRunner, а теперь происходит непосредственно через post_directly_to_runner:

image

Почему же можно так просто переключиться? На самом деле, это то, что мы уже обсуждали ранее — движок Engine не заботится о том, в каком потоке выполняется Runner; для Flutter Engine важно лишь то, чтобы задачи могли быть отправлены в Runner, и чтобы они были выполнены где-то.

Для Dart внутренний VM использует пулы потоков, такие как dart::ThreadPool, для управления системными потоками, и код строится вокруг концепции dart::ThreadPool::Task, а не вокруг конкретных системных потоков:> Например, дефолтная реализация цикла событий для обработки сообщений изолятов фактически не имеет отдельного потока событий; вместо этого dart::MessageHandlerTask публикуется в пуле потоков при появлении нового сообщения.

Также, поскольку ранее потоки UI и Platform были разделены, все UI Runner использовали отдельные MessageLoopTaskQueues для обработки микрозадач, но после объединения потоков UI Runner превратился в Platform Runner, и естественно, нет больше связанной очереди задач, поэтому требуется ручное обновление микрозадач после выполнения задачи.

image

Микрозадача представляет собой тип задач изолятов с более высоким приоритетом.

Кроме того, большинство операций PostTask стали RunNowOrPostTask, основанными на проверках состояния инициализации MessageLoop для выбора места выполнения:

image

Здесь также стоит обратить внимание на логику инициализации платформенного Runner при слиянии двух потоков, которая показывает, что MessageLoop не будет пустым, следовательно, IsInitializedForCurrentThread будет истинным, то есть задача task() будет выполнена непосредственно в текущем потоке:

image

Аналогично на iOS используется текущий MessageLoop:

image> В действительности, после объединения потоков отдельный поток буферизации Flutter остаётся таким, каким он был, поэтому обычно не следует беспокоиться о том, что анимация Flutter может «непосредственно» влиять на поток Native UI, вызывая замедление.Итак, какие преимущества даёт объединение потоков? Самое очевидное преимущество заключается в том, что на iOS теперь поддерживаются PlatformView с рендерингом без необходимости объединения потока буферизации. Другой случай — это ввод текста, поскольку до этого все взаимодействие происходило через Platform Channel. Асинхронное поведение вызвало множество проблем, таких как:

На iOS IME генерирует быстрый поток событий, а затем читает текст перед тем, как события будут обработаны в UI-потоке и отправлены обратно в платформенный поток. Часто логически требуется синхронный ответ, но из-за ограничений Platform Channel приходится использовать дополнительные затраты для достижения этой цели (постоянное извлечение CFRunLoop).

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

Если же объединить всё в один поток, то FFI сможет выполнять синхронное взаимодействие с платформой, позволяя просто вызывать Dart-код и немедленно получать ответ. Это также позволит лучше сохранять некоторые различия между платформами при вводе текста, вместо того чтобы вынуждать унифицированный API ввода текста через Channel.> Также это поможет уменьшить множественное кэширование текста и состояния в памяти.

Кроме того, это упрощает прямое синхронное выполнение метода shouldOverrideUrlLoading в WebView Android.

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

<meta-data
    android:name="io.flutter.embedding.android.DisableMergedPlatformUIThread"
    android:value="true" />

Эта конфигурация выполняет --no-enable-merged-platform-ui-thread, что меняет метку settings.merged_platform_ui_thread на значение false.

Конечно, цель всей команды Flutter заключается в полном удалении платформенных/message каналов, поэтому будущее полностью асинхронных каналов будет обязательно "уничтожено". Объединение потока для Flutter является неизбежным трендом, аналогично React Native, где синхронные вызовы и взаимодействие являются общими трендами для кросс-платформенного программирования.

Ссылки для справки:

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master