Skip to main content

Dart tour: 16、隔离区(Isolates)

Isolates#

大多数计算机中,甚至在移动平台上,都在使用多核 CPU。为了有效利用多核性能,开发者一般使用共享内存的方式让线程并发地运行。然而,多线程共享数据通常会导致很多潜在的问题,并导致代码运行出错。

为了解决多线程带来的并发问题,Dart 使用 isolate 替代线程,所有的 Dart 代码均运行在一个 isolate 中。每一个 isolate 有独立的事件循环和内存以确保其状态不被其它 isolate 访问。

创建隔离区#

可以使用 Isolate.spawn()Fluttercompute() 函数创建单独的隔离区来进行消耗性能的计算。 新创建的隔离区拥有自己的事件循环和内存,即使原始隔离区是该新隔离区的父级,也不允许其访问。

Isolate.spawn 必须传入一个有且仅有一个参数的函数,不可以不传。

import 'dart:isolate';
void main() async {
Isolate.spawn(isolate, "true");
Isolate.spawn(isolate, "false");
}
void isolate(String data) {
print("isolate ${data}");
}

主隔离区#

默认的隔离区是主隔离区。

print(Isolate.current.debugName); // main

隔离区通信#

在创建隔离区的时候,传入 ReceivePort 可以在外部接收隔离区回传的消息。

import 'dart:io';
import 'dart:async';
import 'dart:isolate';
// 隔离区
late Isolate? isolate;
// 定义隔离区运行的函数
void processLink(SendPort sendPort) {
int counter = 0;
Timer.periodic(new Duration(seconds: 1), (Timer t) {
counter++;
String msg = 'notification ' + counter.toString();
// 向 ReceivePort 发送消息
sendPort.send(msg);
});
}
// 创建隔离区并监听回传的值
Future<void> start() async {
ReceivePort receivePort= ReceivePort();
isolate = await Isolate.spawn(processLink, receivePort.sendPort);
receivePort.listen((data) {
stdout.writeln('Receiving: ' + data);
});
}
void main() async {
stdout.writeln('Starting Isolate...');
await start();
}

销毁隔离区#

这段代码在 VSCode 中有问题: Global evaluation requires a thread to have been loaded。 可以通过命令行运行,这样就不会遇到这个问题。dart xxx.dart

通过 Isolate 对象的 kill 方法中断运行中的隔离区。

// 销毁隔离区
void stop() {
if (isolate != null) {
stdout.writeln('Stopping Isolate...');
isolate?.kill(priority: Isolate.immediate);
isolate = null;
}
}
void main() async {
stdout.writeln('Starting Isolate...');
await start();
// 在此时接收任意输入,就会中断运行(执行stop方法)
stdout.writeln('Press enter key to quit');
await stdin.first;
stop();
stdout.writeln('Bye!');
exit(0);
}

参考链接#