0x00 前言
Flutter中有一个很重要的概念就是isolate,isolate是由一个线程实现的,实现isolate的线程由Flutter创建和管理,除了实现isolate的线程,Flutter还有其余的线程,本篇文章探讨Flutte的threading model(线程模型)。
0x01 Flutter Architecture overview
从图中可以看出Flutter有3部分组成:
- Framework(Dart):我们在写Flutter应用中,直接接触的
- Engine(C/C++):引擎层,提供核心技术,例如:Skia(2D图形渲染库);Dart(一个用于垃圾收集的面向对象语言的VM,DartVM有自己的线程池);shell(不同的平台有不同的shell,例如有Android和iOS的shell)
- Embedder(Platform Specific):嵌入层,为Engine创建和管理线程,作用是把Engine的task runners(任务运行器) 运行在嵌入层管理的线程上。
0x02 Flutter的task runners的分类
上面讲了task runners要运行的线程上,这里的task runners有四种,而且都是运行在不同的线程上(可以运行在同一个线程上,但是出于性能的因素,不建议这么做)。
task runners分为四种:
- Platform Task Runner
- UI Task Runner
- GPU Task Runner
- IO Task Runner
1. Platform Task Runner
- Platform Task Runner运行所在的线程 对应 平台的线程
Android | iOS |
主线程 | 主线程 |
- 功能 嵌入层和Engine层的交互,处理平台(Android/iOS)的消息
- 为什么一定要是平台的主线程? 因为Platform Task Runner的功能是要处理平台的消息,但是平台的API都是只能在主线程调用,所以Platform Task Runner运行所在的平台的线程必须是主线程
- 一个Flutter Engine对应一个Platform Thread(一个Flutter应用启动的时候会创建一个Engine实例,Engine创建的时候会创建一个Platform线程供Platform Task Runner使用)
- 阻塞Platform Thread不会直接导致Flutter应用的卡顿(跟iOS android主线程不同)。尽管如此,也不建议在这个Runner执行繁重的操作,长时间卡住Platform Thread应用有可能会被系统Watchdog强杀。
2. UI Task Runner
- UI Task Runner运行所在的线程 对应到 平台的线程
Android | iOS |
子线程 | 子线程 |
这里很容易让大家误会,因为一看名字,UI Task Runner,第一反应,UI ? 那肯定是在主线程里的,其实并不是,UI Task Runner运行所在的线程 对应到 平台的线程,其实是子线程
- 功能
1)用于执行Dart root isolate代码
2)渲染逻辑,告诉Engine最终的渲染
3)处理来自Native Plugins的消息
4)timers
5)microtasks
6)异步 I/O 操作(sockets, file handles, 等) - Root isolate就是运行在这个线程上,所以isolate就可以理解为单线程,有event loop的架构
- 阻塞这个线程会直接导致Flutter应用卡顿掉帧
- 为了防止阻塞这个线程,我们可以创建其他的isolate,创建的isolate没有绑定Flutter的功能,只能做数据运算,不能调用Flutter的功能,而且创建的isolate的生命周期受Root isolate控制,Root isolate停止,其他的isolate也会停止,而且创建的isolate运行的线程,是DartVM里的线程池提供的
3.GPU Task Runner
- GPU Task Runner运行所在的线程 对应到 平台的线程
Android | iOS |
子线程 | 子线程 |
- 功能
GPU Task Runner主要用于执行设备GPU的指令。在UI Task Runner 创建layer tree,在GPU Task Runner将Layer Tree提供的信息转化为平台可执行的GPU指令。 - UI Task Runner和GPU Task Runner跑在不同的线程。GPU Runner会根据目前帧执行的进度去向UI Task Runner要求下一帧的数据,在任务繁重的时候可能会告诉UI Task Runner延迟任务。这种调度机制确保GPU Task Runner不至于过载,同时也避免了UI Task Runner不必要的消耗。
- 在此线程耗时太久的话,会造成Flutter应用卡顿,所以在GPU Task Runner尽量不要做耗时的任务,例如加载图片的时候,去读取图片数据,就不应该放在GPU Task Runner,而是放在接下来要讲的IO Task Runner
- 建议为每一个Engine实例都新建一个专用的GPU Task Runner线程。
4. IO Task Runner
- IO Task Runner运行所在的线程 对应到 平台的线程
Android | iOS |
子线程 | 子线程 |
- 功能
1)主要功能是从图片存储(比如磁盘)中读取压缩的图片格式,将图片数据进行处理为GPU Runner的渲染做好准备。IO Runner首先要读取压缩的图片二进制数据(比如PNG,JPEG),将其解压转换成GPU能够处理的格式然后将数据上传到GPU。 2)加载其他资源文件 - 在IO Task Runner不会阻塞Flutter,虽然在加载图片和资源的时候可能会延迟,但是还是建议为IO Task Runner单独开一个线程。
0x03 各个平台的线程配置
1.iOS
为每个引擎实例的UI,GPU和IO任务运行程序创建专用线程。所有引擎实例共享相同的Platform Thread和Platform Task Runner。
2.Android
为每个引擎实例的UI,GPU和IO任务运行程序创建专用线程。所有引擎实例共享相同的Platform Thread和Platform Task Runner。
3.Fuchsia
每一个Engine实例都为UI,GPU,IO,Platform Runner创建各自新的线程。
4.Flutter Tester (used by flutter test)
UI,GPU,IO和Platform任务运行器使用相同的主线程。