Flutter线程模型

  • isolate是通过Flutter Engine层面的一个线程来实现的,Flutter Engine线程的创建和管理是由embedder负责的,下面是Flutter Engine的运行架构
  • Platform Task Runner
  • 它是Flutter Engine的主Task Runner,既可以处理与Engine的交互也可以处理来自native平台的交互,他类似与Android Main Thread, IOS的Main Thread。每一个Flutter应用启动的时候都会创建一个Engine实例,Engine创建的时候会创建一个Platform Thread供Platform Runner使用,Flutter Engine中很多模块都是废县丞安全的,即使Platform Thread被阻塞,也不会直接导致应用卡顿,但是尽量不要长时间卡住Platform Thread,避免应用被系统的WatchDog强行中止。
  • UI Task Runner
  • 它用于执行Dart root isolate代码,Root isolate在引擎启动的时候绑定了不少flutter所需要的方法,从而使其具备调度/提交/渲染帧的能力,该流程如下
  • Root isolate通知Flutter Engine有帧需要渲染
  • 渲染会生成Layer Tree并交给Flutter Engine, 但是此时仅仅生成了需要哦描绘的内容
  • 创建并更新Layer Tree,这个Layer Tree会决定显示在屏幕上的内容
  • 除了渲染相关逻辑之外Root Isolate还是处理来自Native Plugins的消息,Timers,Microtasks和异步IO等操作。Root Isolate负责创建管理的Layer Tree最终决定绘制到屏幕上的内容。因此这个线程的过载会直接导致卡顿掉帧。
  • GPU Task Runner
  • 它用于执行与设备GPU相关的调用,它可以将UI Task Runner 生成的Layer Tree所提供的信息转化为实际的GPU指令。GPU Runner会根据目前帧被执行的进度向UI Task Runner要求下一帧的数据,在任务繁重时,UI Task Runner会延迟任务进程,这种机制来确保GPU Task Runner 不至于出现过载现象,同时避免了UI Task Runner不必要的消耗
  • IO Task Runner
  • IO Task Runner 的运行线程也对应着平台的子线程,我们发现之前三个Runner对耗时操作比较敏感,当他们出现过载的时候,都会伴随着应用的卡顿。所以IO Task Runner来负责他们处理不了的任务—IO操作。IO Runner的主要功能是做一些预先处理的读取操作,然后将准备好的数据上交给GPU Runner。仿佛IO Runner是GPU Runner的一个助手

isolate

  • 在Flutter中所有dart代码都是在isolate上运行的即dart程序的并发都是运行多个isolate的结果,通常情况下,应用都是运行在main isolate中,但是isolate是有自己的内存和单线程控制的运行实体,在内存上是完全隔离的,所以多个isolate之间无法共享内存,必须通过port通信才可以,这也是他和线程之间的区别

创建单独的isolate(仍受Root isolate控制)

  • 正如上面谈到的isolate和线程之间的区别,创建一个单独的isolate,可以在UI Task Runner运算量过大的时候,单独进行数据运算,所以单独的isolate显得比较重要:
import 'dart:isolate';

main() async {

// isolate的创建必须要有通过ReceivePort创建的SendPort
final receivePort = new ReceivePort();


// 创建Isolate
await Isolate.spawn(_isolate, receivePort.sendPort);


// 发送第一个message(即sendPort)
var sendPort = await receivePort.first;


// 发送信息
var message = await sendReceive(sendPort, "Send1");
print('received $message');
message = await sendReceive(sendPort, "Send2");
print('received $message');
}


// 入口函数
_isolate(SendPort sendPort) async {
// 实例化一个ReceivePort以接收消息
var port = new ReceivePort();


// 将传入的sendPort发送给当前Isolate, 以便当前Isolate可以给他发送消息
sendPort.send(port.sendPort);


// 监听port并从中获取消息
await for (var message in port) {
var data = message[0];
SendPort replyTo = message[1];
replyTo.send('reply: ' + data);
// print('reply' + data);
// print('reply' + replyTo.toString());
if (message[0] == "Send2") {
port.close();
}
}
}


Future sendReceive(SendPort sendPort, message) {
ReceivePort receivePort = new ReceivePort();
// 将信息传递给宿主Isolate
sendPort.send([message, receivePort.sendPort]);
// 返回当前Stream,类似一个管道
return receivePort.first;
}
  • 代码执行流程:main->创建单独的isolate->snedReceive并将当前发的receivePort的sendPort传入->sendPort将信息发送给宿主Isolate->_Isolate将信息读取并发送回main->main中将结果打印出来
  • 运行结果:
received reply: Send1
received reply: Send2