不知道大家有没有一个疑问:Dart是单线程执行,那它是如何实现异步操作的呢?
本文将对Dart/Flutter提供的Isolate
,Event Loop
,Future
,async/await
等进行异步操作相关的知识点进行分析。
Isolate
什么是Isolate?
An isolate is what all Dart code runs in. It’s like a little space on the machine with its own, private chunk of memory and a single thread running an event loop.
- Isolate相当于
Dart
语言中的线程Thread
,是Dart/Flutter
的执行上下文环境(容器); - Isolate有自己独立的内存地址和
Event Loop
,不存在共享内存所以不会出现死锁,但是比Thread
更耗内存;
- Isolate间不能直接访问,需凭借
Port
进行通信;
Main Isolate
当执行完main()
入口函数后,Flutter会创建一个Main Isolate。一般情况下任务都是在这个Main Isolate中执行的。
多线程
一般情况下在Main Isolate执行任务是可以接受的,但是把一些耗时操作放在Main Isolate中执行,会造成掉帧的现象,这会对用户体验造成严重影响。此时,选择将耗时任务分发到其他的Isolate中就是一个很好的实现方式了。
所有的Dart Code都是在Isolate
中执行的,代码只能使用同一个Isolate
中的内容,不同的 Isolate
是内存隔离的,因此只能通过 Port 机制发送消息通信,其原理是向不同的 Isolate 队列中执行写任务。
案例
我们做了个简单的Demo,屏幕中间有一个心在不停的动画(由小变大,再由大变小)。当我们点击右下角对的加号按钮,会进行一个耗时的运算。如果耗时操作在Main Isolate执行,将会造成界面的丢帧,动画将会出现卡顿的情况。
我们目前就是需要解决这个掉帧的问题。
1.compute
方法
Flutter封装了一个compute
这个高级API函数可以让我们方便的实现多线程的功能。
Future<R> compute<Q, R>(isolates.ComputeCallback<Q, R> callback, Q message, { String? debugLabel }) async {
}
compute
接收两个必传参数:1,需要执行的方法;2,传入的参数,这参数最多只能是1个,所以多个参数需要封装到Map
中;
- 最开始的代码
// 耗时操作的方法:`bigCompute`
Future<int> bigCompute(int initalNumber) async {
int total = initalNumber;
for (var i = 0; i < 1000000000; i++) {
total += i;
}
return total;
}
// 点击按钮调用的方法:`calculator`
void calculator() async {
int result = await bigCompute(0);
print(result);
}
// FloatingActionButton的点击事件
FloatingActionButton(
onPressed: calculator,
tooltip: 'Increment',