Isolate简介
什么是Isolate
isolate就像是机器上的一个小空间,带有自己的私有内存块和一个运行事件循环的线程。
两个Isolate,每个Isolate都有自己的内存和执行线程。
Isolate的作用
如果要执行的计算量很大,在主Isolate中运行可能会导致丢帧,则可以使用Isolate.spawn()或Flutter的compute()函数。这两个函数都创建了一个单独的Isolate程序进行越暖,使主Isolate程序可以自由地进行其他操作(例如:Flutter中的重建和渲染小部件树)。
PS:阅读源码可知
Flutter的compute()函数是对Isolate.spawn()的封装
多个Isolate如何一起工作
Isolate通过互相传递消息一起工作。一个Isolate将消息发送到另一个,接收消息的Isolate使用其事件循环处理该消息。
创建Isolate
使用Isolate类下的静态方法spwan来创建Isolate
Isolate.spawn方法
下面来介绍一下Isolate.spawn方法的参数
-
必填参数
entryPoint: 它是Isolate程序中调用的初始函数。该函数必须是顶级函数或静态方法,且该函数必须有一个和isolate的参数message同种类型的参数。 -
必填参数
message: 它的作用就是为entryPoint函数提供参数,值得一提的是message通常包含一个SendPort,以便不同的isolate进行通信。 -
可选参数
paused: 如果paused参数设置为true,Isolate将以暂停状态启动。暂停状态启动就像是调用entryPoint函数之前,调用了isolate.pause(isolate. pausecapability),我们能直接看到的效果就是如果Isolate以暂停状态启动,entryPoint函数并不会执行。如果想要恢复Isolate程序,调用isolate.resume(isolate. pausecapability)。值得一提的是:
Isolate暂停功能通过暂停事件队列来工作。当前正在执行的事件将完成,直到您恢复Isolate之前,不会再处理其他事件。暂停不会影响正在运行的代码。 -
可选参数
errorsAreFatal: 设置未捕获的错误是否将终止Isolate。如果错误是致命的,则任何未捕获的错误都会终止Isolate事件循环并关闭隔离。
Isolate.spawn方法的返回值为Future,如果创建Isolate成功完成,Future的value为Isolate类型。
创建Isolate的例子
创建一个最简单的Isolate
import 'dart:isolate';
void main() {
Isolate.spawn(isolateFunc, "message");
}
isolateFunc(message) {
print(message);
}
输出如下
message
当启动应用程序时,新的Isolate被创建,isolateFunc方法在新创建的Isolate中执行。
到了这一步已经可以满足大部分使用Isolate的场景了,即把会导致UI卡顿的任务用额外的Isolate来执行。
获取Isolate对象的两种方式
Isolate.spwan方法返回的是Future,我们该如何做才能拿到Isolate对象进行操作呢?
-
在Future的then回调中进行赋值操作
Isolate isolate; void main() { Isolate.spawn(isolateFunc, "message").then((value) { isolate = value; }); } isolateFunc(message) { } -
使用async,和await简化第一种方法
Isolate isolate; void main() async { isolate = await Isolate.spawn(isolateFunc, "message"); } isolateFunc(message) {}
Isolate常用方法
kill
请求Isolate终止自身。该函数的priority参数指定何时执行此操作。
priority参数必须是0(immediate)或 1(beforeNextEvent)。根据优先级在不同的时间执行关闭操作:
immediate:Isolate将尽快关闭。控制消息是按顺序处理的,因此来自此Isolate的所有先前发送的事件都将被处理。如果系统有办法在更早的时间彻底关闭,甚至在执行另一个事件期间,也可能会更早发生。beforeNextEvent:计划在当前事件以及所有已调度的事件完成后关闭。
示例:
isolate.kill();
pause
暂停isolate
当isolate收到暂停命令时,它将停止处理来自事件循环队列的事件,已经在事件循环队列中的事件还会继续执行。
示例:
isolate.pause(isolate.pauseCapability);
resume
结束暂停
示例:
isolate.resume(isolate.pauseCapability);
Isolate的通讯
isolate单向通信
Isolate之间的通讯主要是通过ReceivePort类实现的,我们通过一段代码示例来讲解Isolate之间的通讯。
// 导入isolate包
import 'dart:isolate';
void main() async {
// 创建一个ReceivePort用于接收消息
var recv = ReceivePort();
// 创建一个Isolate,泛型参数为SendPort,入口函数为subTask
// subTask入口函数的参数为SendPort类型,因此spawn第二个参数,传入recv的sendPort对象。
Isolate.spawn<SendPort>(subTask, recv.sendPort);
// 使用await等待recv的第一条消息
var result = await recv.first;
print("recv: $result");
}
// Isolate入口函数定义,接收一个SendPort对象作为参数
void subTask(SendPort port) {
// 使用SendPort发送一条字符串消息
port.send("subTask Result.");
}
ReceivePort是Dart中的Stream
上面的例子实现了新创建的Isolate发送消息到main程序。
阅读源码ReceivePort是通过
StreamController创建的Stream
双向通信
//@dart = 2.16
// Example:
import 'dart:async';
import 'dart:isolate';
void main() async {
var isolateReceivePort = ReceivePort();
var isolate = await Isolate.spawn(runIsolate, isolateReceivePort.sendPort);
late SendPort sendPort;
var completer = Completer();
await isolateReceivePort.listen((msg) {
if (msg is SendPort) {
completer.complete(msg);
} else {
print('Received in isolate: $msg');
}
});
sendPort = await completer.future;
sendPort.send("main");
}
//次级isolate创建ReceivePort,监听从其他isolate传来的数据,
// 通过初始化时接到的sendPort将自己创建的receivePort的sendPort发送出去
//主isolate接到sendPort,用这个端口给次级isolate发消息
void runIsolate(SendPort sendPort) {
var receivePort = ReceivePort();
receivePort.listen((msg) {
print('Received in main: $msg');
});
sendPort.send('Message from isolate');
sendPort.send(receivePort.sendPort);
}