Flutter线程模型

摘要

Flutter Engine层面,有四个Runner各司其职,这里的Runner其实就是线程,不过这四个Runner是由Engine和Native之间的那个嵌入层(Embedder)去赋值的,Engine层只会使用这四个Runner,不会创建新的线程。

Platform Task Runner

  • 对应平台的线程的主线程
  • Mobile平台所有Engine实例共享同一个Platform Task Runner和线程;

  • 功能:

    1. 处理与Engine层的交互
    2. 处理平台(Android/iOS)的消息
  • 为什么一定要是平台的主线程? 因为Platform Task Runner使用Platform Channel处理平台的消息,但Platform Channel并非是线程安全,故平台跟Flutter Engine的所有交互必须在平台的主线程中执行的,所以Platform Task Runner运行所在的平台的线程必须是主线程;

  • 尽管阻塞该线程并不会影响Flutter渲染管道导致页面卡顿,但主线程建议不要执行耗时操作,否则可能触发Watchdog来结束该应用。比如Android、iOS都是使用平台线程来传递用户输入事件,一旦平台线程被阻塞则会引起手势事件丢失。

UI Task Runner

  • 对应平台的线程的子线程

  • 功能:

    1. 用于 Flutter Engine 执行 Root Isolate 中的所有Dart代码
    2. 执行渲染与处理Vsync信号,将Widget转换生成Layer Tree
    3. 处理来自Native Plugins的消息
    4. Timers
    5. Microtasks
    6. 异步 I/O 操作(sockets, file handles, 等)
  • 阻塞这个线程会直接导致Flutter应用卡顿掉帧。为了防止阻塞这个线程,我们可以创建其他的Isolate,创建的Isolate没有绑定Flutter的功能,只能做数据运算,不能调用Flutter的功能,而且创建的Isolate的生命周期受Root Isolate控制,Root Isolate停止,其他的Isolate也会停止,而且创建的Isolate运行的线程,是DartVM里的线程池提供的;

GPU Task Runner

  • 对应平台的线程的子线程

  • 功能:

    1. 主要用于执行设备GPU的指令:在UI Task Runner 创建Layer Tree,在GPU Task Runner将Layer Tree提供的信息转化为平台可执行的GPU指令;
  • UI Task Runner和GPU Task Runner跑在不同的线程。GPU Task Runner会根据目前帧执行的进度去向UI Task Runner要求下一帧的数据,在任务繁重的时候可能会告诉UI Task Runner延迟任务,例如基于Layer Tree的处理时长和GPU帧显示到屏幕的耗时,GPU 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线程。

IO Task Runner

  • 对应平台的线程的子线程

  • 功能:

    1. 主要功能是从图片存储(比如磁盘)中读取压缩的图片格式,将图片数据进行处理为GPU Task Runner的渲染做好准备。IO Task Runner首先要读取压缩的图片二进制数据(比如PNG,JPEG),将其解压转换成GPU能够处理的格式然后将数据上传到GPU。
    2. 加载其他资源文件
  • 在IO Task Runner不会阻塞Flutter,虽然在加载图片和资源的时候可能会延迟,但是还是建议为IO Task Runner单独开一个线程。

参考

  1. 深入理解Flutter引擎线程模式
  2. Flutter的thread model