阅读 1142

深入了解Flutter的isolate(3) --- Flutter的thread model(线程模型)

0x00 前言

Flutter中有一个很重要的概念就是isolate,isolate是由一个线程实现的,实现isolate的线程由Flutter创建和管理,除了实现isolate的线程,Flutter还有其余的线程,本篇文章探讨Flutte的threading model(线程模型)。

0x01 Flutter Architecture overview

从图中可以看出Flutter有3部分组成:

  1. Framework(Dart):我们在写Flutter应用中,直接接触的
  2. Engine(C/C++):引擎层,提供核心技术,例如:Skia(2D图形渲染库);Dart(一个用于垃圾收集的面向对象语言的VM,DartVM有自己的线程池);shell(不同的平台有不同的shell,例如有Android和iOS的shell)
  3. Embedder(Platform Specific):嵌入层,为Engine创建和管理线程,作用是把Engine的task runners(任务运行器) 运行在嵌入层管理的线程上。

0x02 Flutter的task runners的分类

上面讲了task runners要运行的线程上,这里的task runners有四种,而且都是运行在不同的线程上(可以运行在同一个线程上,但是出于性能的因素,不建议这么做)。

task runners分为四种:

  1. Platform Task Runner
  2. UI Task Runner
  3. GPU Task Runner
  4. 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任务运行器使用相同的主线程。

关注下面的标签,发现更多相似文章
评论