5分钟了解Flutter线程Isolate的运用以及Isolate到底是什么
- Isolate在dart是什么
- flutter线程内存隔离
- Isolate的使用
- 第一种,无参数
- 使用Isolate.run
- 第二种,有参数
- 使用compute:
- 使用Isolate.spawn
- Isolate与外面线程通讯
- Isolate以文件形式加载到内存运行
- Isolate运用场景
- Isolate到底是不是真的线程
- 如何证明Isolate不是真的线程?
Isolate在dart是什么
Isolate中文的意思是“隔离”。用宏观角度来看,在dart使用Isolate,相当于使用线程。
我们来看看官方给出的解析:
"所有 Dart 代码都在isolate中运行,isolate与线程类似,但不同之处在于isolate有自己的isolate内存。 它们不以任何方式共享状态,只能通过消息传递进行通信。 默认情况下,Flutter 应用程序在单个isolate区(主isolate区)上完成所有工作。 在大多数情况
但有时,应用程序需要执行异常大的计算,这可能会导致“UI jank”(不稳定的运动)。 如果您的应用程序因此而遇到卡顿,您可以将这些计算移至辅助isolate中。 这允许底层运行时环境与主 UI isolate的工作同时运行计算,并利用多核设备。
每个isolate区都有自己的内存和事件循环。 事件循环按照事件添加到事件队列的顺序处理事件。 在主isolate区上,这些事件可以是任何事件,从处理用户在 UI 中点击、执行功能到在屏幕上绘制框架。 "
flutter线程内存隔离
我们从下面这张官方给出的图,可以发现Dart虚拟机与Android虚拟机截然不同的是,运行中的Isolate是内存独立的。
显而易见,Isolate的最大优势就是创建线程不需要对内存加锁,创建速度快,。并且垃圾回收不需要暂停其他业务线程,可以隔绝其他业务线程带来的内存抖动的影响,从而优化业务了帧率(不熟悉内存抖动,可以看看这篇文章<<Android内存抖动>>)。但是缺点也明显,内存不共享,通讯需要拷贝内容。
Isolate的使用
第一种,无参数
使用Isolate.run
String runData = await Isolate.run(<String>() {
return 'run ,run run';
});
print("Isolate.run:$runData");
运行结果:
Isolate.run:run ,run run
第二种,有参数
可以使用函数compute, 也可以使用Isolate.spawn
使用compute:
class Data {
String value = 'data';
}
String computeData = await compute((message) {
print("compute>>:${message.value}");
return 'kakakak';
}, Data()..value = 'compute,compute');
print("compute.run:$computeData");
运行结果:
Shell: compute>>:compute,compute
compute.run:kakakak
使用Isolate.spawn
await Isolate.spawn((message) {
print('Isolate.spawn:${message.value}');
}, Data());
运行结果:
Shell: Isolate.spawn:data
Isolate与外面线程通讯
RawReceivePort相当于接收器,里面有个订阅回调,接收Isolate返回的数据
final receivePort = RawReceivePort();
receivePort.handler = (data) {
print(data);
if (data == 'close') {
receivePort.close();
}
};
Isolate.spawn((port) {
var i = 0;
while (i < 5) {
port.send('create:${i++}');
}
port.send('close');
}, receivePort.sendPort);
运行结果:
Shell: create:0
Shell: create:1
Shell: create:2
Shell: create:3
Shell: create:4
Shell: close
Isolate以文件形式加载到内存运行
提供个dart文件,然后使用Isolate.spawnUri这个方法加载这个文件执行。但是入口必须是如下
void main(List<String> args,SendPort sendPort){
}
下面提供完整的例子:
编写一个dart文件,名字可以任意取,这里叫做isloate_test.dart
import 'dart:convert';
import 'dart:isolate';
void main(List<String> args,SendPort sendPort){
print(jsonEncode(args));
}
然后在其他dart文件加载
ReceivePort receiveUriPort = ReceivePort();
await Isolate.spawnUri(
Uri(path: './isloate_test.dart'), ['a', 'b', 'c'], receiveUriPort.sendPort);
运行结果:
[‘a’, ‘b’, ‘c’]
Isolate运用场景
由于UI代码是在UI线程里面执行的,为了避免影响UI线程的运算,非UI的业务都建议使用其他线程来进行执行,以优化UI的流畅度
Isolate到底是不是真的线程
微观角度来看,Isolate真不是具体的线程,它只是dart运输到线程执行的一种包装载体。并且是放到系统的线程池里面执行的一种包装。
Isolate是由Dart VM Thread从系统里面进行创建来调度管理的。 Isolate类似Java的Runnable
如何证明Isolate不是真的线程?
很简单,你只需要跑到 点击>>isolate.cc<<的源码里面阅读一下就可以知道它是交给tread_pool线程池执行的。
//...
isolate->group()->thread_pool()->Run<SpawnIsolateTask>(isolate,
std::move(state));
//...
是不是很赞?如果这篇文章对你有帮助,请关注🙏,点赞👍,收藏😋三连哦