void send(Object? message);
耗时严重, 达秒级, 顿了一下, 页面才刷新的感觉( 未解决 )Dart 是单线程语言. Flutter 依赖于Dart
Dart的 “线程” 是指 isolate.
isolate 与线程的区别: isolate 之间是内存独立的, isolateA 不能访问isolateB的内存数据.
Future 可以实现异步.异步但串行非并发执行任务
单线程并不是说 Dart 只有一个线程! Dart可以创建子 isolate 实现多线程.
loop内有两个FIFO队列
- microask queue
- event queue (里面就是Future任务)
前者执行优先级高于后者, 如图
官方async-await描述
1. future 是Future 的实例对象, future 代表一个异步操作的结果, 它有两种状态: 未完成和已完成.
2. await 可以修饰函数/, 如果该函数返回值为Future 类型, 则会阻塞当前流程, 等待被修饰的函数执行完成后继续执行后续代码. 函数内使用 await 的前提是该函数是一个 async 函数. 也就是说 await 要和 async 配对使用.
3. 但是 async 函数内可以没有 await 关键字.
总结: await future 会阻塞流程
函数内有阻塞流程(await future)的操作, 则函数会返回一个 future 实例
(1) 如果该函数本身有返回值, 比如类型为T, 则返回类型为Future
(2) 如果该函数本身没有返回值, 则返回类型为 Future
比如下面的 funcTest 函数会返回 Future
funcTest() async {
await Future((){
print('funcTest end');
});
}
一个async函数同步运行直到第一个 await关键字。这意味着在async函数体内,第一个await关键字之前的所有同步代码都会立即执行。
版本说明: 在 Dart 2.0 之前,async函数立即返回,不执行async函数体内的任何代码。
例子:
void main() async {
print('main begin');
funcB();
print('main end');
}
funcB() async {
print('funcB begin');
await Future.delayed(Duration(seconds: 2), (){
print('funcB delayed over');
});
print('funcB end');
}
funcB 虽然是异步函数, 但是在main函数执行到funcB时并不会跳过去打印’main end’, 而是继续执行funcB , 直到遇到funcB的第一个await关键字后返回.
打印结果:
main begin
funcB begin
main end
funcB delayed over
funcB end
官方event-loop描述
1. 立刻把任务加入 event queue, 用 Future():
// Adds a task to the event queue.
new Future(() {
// …code goes here…
});
2. some time 后把任务加入(并非执行!) event queue用 Future.delayed():
// After a one-second delay, adds a task to the event queue.
new Future.delayed(const Duration(seconds:1), () {
// …code goes here…
});
注意: Future 或 Future.delayed 的返回值是Future类型还是 Future 类型, 取决于执行函数有无返回值, 有返回值就是前者, 无返回值就是后者; 可以把执行函数理解成上文的异步函数
执行main函数:
await funcC();
等同于 funcC();
await funcD();
所以要等 funcD 函数全部执行完成, 才会打印 'main end’void main() async {
print('main begin');
funcA();
funcB();
await funcC();
await funcD();
print('main end');
}
funcA() {
print('funcA');
}
funcB() async {
print('funcB begin');
// 2s后把执行函数加入 event loop, 且执行函数变成完成状态才会执行下面的 'funcB end'
await Future.delayed(Duration(seconds: 2), (){
print('funcB delayed over');
});
print('funcB end');
}
funcC() async {
print('funcC begin');
// 2s后把执行函数加入 event loop
Future.delayed(Duration(seconds: 2), (){
print('funcC delayed over');
});
print('funcC end');
}
funcD() async {
print('funcD begin');
// 2s后把执行函数加入 event loop, 且执行函数变成完成状态才会执行下面的 'funcD end'
await Future.delayed(Duration(seconds: 2), (){
print('funcD delayed over');
});
print('funcD end');
}
我们平时写的代码就运行在flutter创建好的UI线程. 当运行耗时代码时页面会有卡顿感, 就是掉帧了.
解决方案: 开辟新线程处理耗时操作, 把处理结果传给 UI 线程刷新页面.
Dart 开辟新线程的方式是使用 isolate.
isolate 与普通线程的区别在于: isolate之间是内存隔离的!!!.
比如: isolate A 内不能访问 isolate B 的变量
此时好像就结束了, 但是! 官方isolate有一个致命局限性…
我们自己创建的isolate内是没办法使用插件的. 原因是Platform-Channel的通信只能在主isolate内执行
在Stack Overflow 发现两个插件, 可以完美解决这个问题:
但是当我感觉终于要看到胜利的曙光时我发现,
这个方法耗时达秒级(把子isolate执行完毕的结果发送给主isolate)
abstract class SendPort implements Capability {
/// Sends an asynchronous [message] through this send port, to its
/// corresponding `ReceivePort`.
///
/// The content of [message] can be: primitive values
/// (null, num, bool, double, String), instances of [SendPort],
/// and lists and maps whose elements are any of these.
/// List and maps are also allowed to contain cyclic references.
///
/// In the special circumstances when two isolates share the same code and are
/// running in the same process (e.g. isolates created via [Isolate.spawn]),
/// it is also possible to send object instances (which would be copied in the
/// process). This is currently only supported by the
/// [Dart Native](https://dart.dev/platforms#dart-native-vm-jit-and-aot)
/// platform.
///
/// The send happens immediately and doesn't block. The corresponding receive
/// port can receive the message as soon as its isolate's event loop is ready
/// to deliver it, independently of what the sending isolate is doing.
void send(Object? message);
}
如果这样, isolate的使用场景就变得很少了, 也只能后台任务不需要刷新页面的情况下使用了
参考: futures-isolates-event-loop