Flutter Engine 线程模型

Flutter Engine 线程模型

Flutter 的架构

Flutter 主要分为三个核心模块

Framework:基于 Dart 语言构建的 framework,包括了动画以及各种组件

Engine:基于 C/C++ 构建的引擎,包括了 Skia 和 DartVM, 以及在不同平台实现的 shell 层,Engine 通过封装好的 Embedder API 去调用不同平台的能力

Embedder:嵌入层,将 Flutter 嵌入到各个平台上。Embedder 负责范围包括原生平台插件、线程管理、事件循环等。
Flutter 架构

Engine 线程

Flutter Engine 自己并不创建和管理线程,线程的创建和管理全都由 Embedder 负责,Embedder 提供 Task Runner 给 Engine,除了 Engine 使用的 Runner 之外,DartVM 还有自己的线程池,但这些都是 Engine 和 Embedder 无法访问的。DartVM 中的线程池主要是用来实现语言特性比如异步等的,后面另开文章介绍吧。

Engine 需要 Embedder 提供四个 Task Runner,这四个 Runner 是否在同一个线程还是多个线程都可以,只要在 Engine 的生命周期内保持稳定,Runner 不要切换线程就可以,但为了获得更好的性能还是建议每个 Runner 都有专用的线程。

Platform Task Runner

Platform Runner 是运行在平台的主线程上的,对 Flutter Engine 的所有操作都必须在 Platform 的线程中,Flutter 中的很多 API 都不是线程安全的,在其他的线程中操作都有可能会导致异常。

阻塞 Platform Thread 不会直接导致 Flutter 应用卡顿,但是如果长时间卡主 Platform Thread 也就是平台的主线程有可能会被系统强杀。

UI Task Runner

UI Task Runner 是执行 Dart root isolate 的地方,root isolate 稍微特殊一点,它绑定了很多函数,这个 isolate 也就是运行应用所有 dart 代码的地方,绑定的函数可以提交渲染帧给 Engine,供 Engine 去渲染:

1. Root isolate 通知 Flutter Engine 有帧需要渲染
2. Flutter Engine 通知平台,需要在下一个 vsync 的时候得到通知
3. 平台等待下一个vsync
4. 对 Widgets进行布局操作,并生成页面的显示信息的描述,并提交给 Engine
生成 Layer Tree 过程

除了渲染相关逻辑之外 Root Isolate 还处理来自 Platform Plugins 的事件,Timers,Microtasks 和异步 IO 等操作。Root Isolate 负责创建管理的 Layer Tree 最终决定绘制到屏幕上的内容,因此这个线程的过载会直接导致卡顿掉帧。

对于计算量比较大的任务,也可以使用例如 compute 方法去创建一个新的 isolate 去执行,新的 isolate 是运行在 DartVM 线程池中的某个线程,而且没有 Flutter framwork 的绑定,不能操作 UI 和提交渲染帧给 Engine,所以非 root 的 isolate 只能用来做计算。

GPU Task Runner

GPU Task Runner 主要用于执行设备 GPU 的指令。UI Task Runner 创建的 Layer Tree 是跨平台的,它不关心到底由谁来完成绘制。GPU Task Runner 负责将 Layer Tree 提供的信息转化为平台可执行的GPU指令。GPU Task Runner 同时负责绘制所需要的GPU资源的管理。资源主要包括平台 Framebuffer,Surface,Texture 和 Buffers等。

一般来说 UI Runne r和 GPU Runne r跑在不同的线程。GPU Runner 会根据目前帧执行的进度去向 UI Runner 要求下一帧的数据,在任务繁重的时候可能会告诉 UI Runner 延迟任务。这种调度机制确保 GPU Runne r不至于过载,同时也避免了 UI Runner 不必要的消耗。

IO Task Runner

前面的几个 Runner 对于执行流畅度有比较高的要求。Platform Runner 过载可能导致系统WatchDog 强杀,UI 和 GPU Runner 过载则可能导致 Flutter 应用的卡顿。因此一些比较耗时的操作,图片读取、解压、渲染等操作,就放在 IO Runner 中进行处理

IO Runner 的主要功能是读取压缩的图片格式,将图片数据进行处理为 GPU Runner 的渲染做好准备。但是只有 GPU Runner 才能对GPU提交渲染信息,为了保证 IO Runner 也具备这个能力,所以 IO Runner 会引用 GPU Runner 的 context,这样就具备向GPU提交渲染信息的能力。

IO Runner 读取图片将其解压转换成GPU能够处理的格式并上传到GPU。IO Runner 直接决定了图片和其它一些资源加载的延迟间接影响性能。

iOS 和 Android 线程配置

移动平台上每一个 Engine 实例启动的时候会为 UI,GPU,IO Runner 各自创建一个新的线程,所有的 Engine 实例共享同一个 Platform Runner 和线程

Fuchsia 线程配置

每一个 Engine 实例都为 UI,GPU,IO,Platform Runner 创建各自新的线程

编辑于 2019-04-28 13:02