[TOC]
dart是一种单线程语言,异步模型主要是通过事件轮询(event loop)来实现,另外也提供了更高级的Isolate来支持多线程,通常用于计算比较耗时的操作。
dart中的事件轮询包含两种事件队列:MicroTask和 EventTask,其中经常使用的属于EventTask队列,MicroTask并不常用,也不推荐使用。
dart中的事件轮询看起来像这样:(摘自Flutter异步编程)
void eventLoop(){
while (microTaskQueue.isNotEmpty){
//执行MicroTask队列
}
if (eventQueue.isNotEmpty){
//执行Event队列
}
}
从上面代码可以看出来,每次事件轮询总是先执行完MicroTask中的事件。
创建MicroTask有两种方法:
//第一种:使用全局静态方法创建
scheduleMicrotask((){
print('this is a MicroTask demo');
});
//第二种:使用Future.microTask方法创建
var result=await Future.microtask((){
return "this is a MicroTask demo";
});
print(result);
从使用API上可以看出使用Future.microtask
的好处是允许我们有一个返回值(内部通过Future包裹实现),而scheduleMicrotask
则不支持返回值。
这是一种常用的事件队列,比如await/async,Timer,Future,Stream等,除了MicroTask
之外的所有事件。
async
标记一个方法将要返回一个Future
对象,该对象是可以被await
的,dart中异步的一个重要标识就是await
,每当遇到一个await
时,dart都会等待await
的Future
执行完成后再执行后面的代码。
await/async
只是用来简化Future的语法糖
而已。
//如果你希望一个方法时异步执行的,首先它要有一个async标记
Future foot(int index) async{
await Future.delayed(Duration(seconds: 1));
print(index);
}
void main() async{
print(1);
//await可以让这个代码同步执行
await foot(2);
print(3);
//没有await标记,代码将异步执行
foot(4);
print(5);
}
//下面时执行结果,是否符合你的预期:
1
2
3
5
4
Timer是dart中的定时器,支持立即(Timer.run()),延迟(Time()),间隔(Timer.periodic())3种执行方式。
因为dart是单线程运行的所以Timer
的执行也是需要在EventTask
队列中排队执行的。下面这段代码演示Timer也要写入EventTask
队列中才能运行:
import 'dart:async';
void main() async {
//立即执行
Timer.run(() {
print('timer 0');
});
//延迟2s执行
Timer(Duration(seconds: 2), () {
print('timer 2');
});
var begin = DateTime.now();
//使用循环延迟1s,
//使用这种方式的好处是,一旦循环开始必须结束才会执行其它操作
while (true) {
var microseconds = DateTime.now().difference(begin).inMicroseconds;
if (microseconds > 1000) {
print('timer');
break;
}
}
//dart提供类sleep函数来提供等待功能
sleep(Duration(seonds:1));
//延迟1s
Timer(Duration(seconds:1),(){
print(('timer 1'));
});
}
//执行结果:
timer
timer 0
timer 1
timer 2
代码开头我们定义了一个立即执行Timer,但是先执行的却是while代码块,说明Timer只是向事件循环中添加了一个任务,while代码块延迟1s,所以先被添加到事件循环的就是延迟1s的Timer,这也说明只有到了延迟时间才会将后续要执行的代码放进事件循环,而不是在定义的时候就放进去的。
Future
是Timer
的加强版本,一个Timer
通常只处理一个无返回值的函数,Future对Timer进行了包装。Future是一个异步处理对象,所有的异步操作都返回一个Future对象,Future不是最终的返回值,只是一个异步状态值,你可以对一个Future对象使用await来等待异步操作完成。
Future()
//使用Future可以很容易的创建一个异步运行的匿名方法
var result=await Future((){
print('返回一个bool值');
return true;
});
print(result);
Future.delayed()
//延迟异步执行一个方法
result=await Future.delayed(Duration(seconds: 1),(){
print('延迟返回一个bool值');
return true;
});
print(result);
Future.wait()
//等待异步方法完成,wait可以保证所有的future都是按照顺序执行
//相当于:
// await future1;
// await future2;
// await future3;
var future1=Future.delayed(Duration(seconds: 5),(){
return '第1个Future完成';
});
var future2=Future((){
return '第2个Future完成';
});
var future3=Future.delayed(Duration(seconds: 1),(){
return '第3个Future完成';
});
print('等待Futures完成');
var results =await Future.wait([future1,future2,future3]);
for (var item in results) {
print(item);
}
Future.any()
//当任何一个future完成时结束
var anyFuture1=Future.delayed(Duration(seconds: 5),(){
return '第一个Future';
});
var anyFuture2=Future((){
return '第二个Future';
});
var anyFuture3=Future.delayed(Duration(seconds: 2),(){
return '第3个Future';
});
print('等待最快完成的Future');
var item = await Future.any([anyFuture1,anyFuture2,anyFuture3]);
print(item);
Future.forEach()
//使用Future遍历Iterable<T>对象,
//下面对比普通的forEach与Future.forEach的区别
[3,2,1].forEach((item) async{
await Future.delayed(Duration(seconds: item));
print('forEach item $item');
});
//Future.forEach总是按顺序执行
await Future.forEach([3,2,1], (item) async{
await Future.delayed(Duration(seconds: 1));
print('Future.forEach item $item');
});
Future.doWhile()
//启动一个Future,直到返回值为false时结束
var index=0;
await Future.doWhile((){
print('doWhile item ${index++}');
return index!=10;
});
Future.sync
//直接执行sync中传递的方法,始终返回一个Future
//下面的代码可以看到返回结果始终时一个Future
var syncResult1=await Future.sync((){
return "无async标记";
});
print(syncResult1);
var syncResult2=await Future.sync(() async{
return '有async标记';
});
print(syncResult2);
Future.microtask()
//创建一个MicroTask任务
Future.microtask((){});
Future.value()
//从值对象构造一个Future
var future=await (){
//等价:Future.sync(()=>'future执行结果');
return Future.value('future执行结果');
}();
print(future);
Future.error()
//创建一个错误返回值的Future
var failedFuture=await (){
return Future.error('创建一个错误返回值的Future');
}();
print(failedFuture);
}
下面这张图演示了Stream的运行原理:
下面有两段官方提供的代码足以搞懂他们的区别:
dart是一个单线程程序,在执行耗时的操作是会导致线程卡住,尤其在Flutter上会导致ui卡顿。
isolate优点是将耗时的代码放在一个独立的线程中执行,缺点是不能共享其它线程的实例成员,有点类似进程间的数据隔离。
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
computer(SendPort port) async {
var receivePort = ReceivePort();
// 向client暴漏自己的可通信对象
port.send(receivePort.sendPort);
Future(() async {
//监听client消息
await for (var data in receivePort) {
print(data);
sleep(Duration(seconds: 1));
port.send(++data);
}
});
}
main(List<String> args) async {
var receivePort = ReceivePort();
// isolate要求第一个参数不能是匿名方法
// 如果将第一个参数作为server端,那么第二参数就是客户端,server端通过这个参数来与client端交互
await Isolate.spawn(computer, receivePort.sendPort);
var stream = receivePort.asBroadcastStream();
// 接收server端的可通信对象,用于发送数据
SendPort sendPort = await stream.first;
// 发送一个数据
sendPort.send(0);
Future(() async {
// 监听收到的server端消息
await for (var data in stream) {
print(data);
sleep(Duration(seconds: 1));
sendPort.send(++data);
}
});
}