# Event loop

[TOC]

​ dart是一种单线程语言,异步模型主要是通过事件轮询(event loop)来实现,另外也提供了更高级的Isolate来支持多线程,通常用于计算比较耗时的操作。

# Event loop

​ dart中的事件轮询包含两种事件队列:MicroTaskEventTask,其中经常使用的属于EventTask队列,MicroTask并不常用,也不推荐使用。

dart中的事件轮询看起来像这样:(摘自Flutter异步编程)

void eventLoop(){
    while (microTaskQueue.isNotEmpty){
     //执行MicroTask队列
    }

    if (eventQueue.isNotEmpty){
     //执行Event队列
    }
}

从上面代码可以看出来,每次事件轮询总是先执行完MicroTask中的事件。

# 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则不支持返回值。

# EventTask

​ 这是一种常用的事件队列,比如await/async,Timer,Future,Stream等,除了MicroTask之外的所有事件。

# await/async

async标记一个方法将要返回一个Future对象,该对象是可以被await的,dart中异步的一个重要标识就是await,每当遇到一个await时,dart都会等待awaitFuture执行完成后再执行后面的代码。

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定时器

​ 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

FutureTimer的加强版本,一个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

下面这张图演示了Stream的运行原理:

# MicroTask与EventTask的执行顺序对比:

下面有两段官方提供的代码足以搞懂他们的区别:

  1. https://dart.dev/articles/archive/event-loop#question-1
  2. https://dart.dev/articles/archive/event-loop#question-2

# Isolate

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);
    }
  });
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • # Dart Socket之TCP粘包

    * RawServerSocket、RawSocket、ServerSocket、Socket

    用户1175783
  • FNV哈希算法

    用户1175783
  • # Futter入门到精通

    文笔不行写不出高深的理论,只能借鉴引用高人的高论了,下面文章的一些连接来自一些国内/外高人的原创或者翻译文章。所谓站在巨人的肩上,就是的是把别人的知识变成自己的...

    用户1175783
  • 零成本异步 I/O (下)

    这个非常出色的基于轮询的新方案——我们编写了这个模型,我归功于 Alex 和 Aaron Turon,是他们提出了这个想法——不是由 Future 来调度回调函...

    MikeLoveRust
  • Dart中的异步操作

    在前面的文章中我们很多次提到了Future这个东西,这个单词翻译过来的意思是‘未来’的意思。在flutter中它表示一个未来某些时候返回数据的一个对象。

    flyou
  • Flutter必备语言Dart教程04 - 异步,库

    现在我们来看看如何在Dart中处理异步代码。使用Flutter时,会执行各种操作,例如网络调用和数据库访问,这些操作都应该异步执行。

    前端知否
  • Java多线程编程-(19)-多线程异步调用之Future模式

    在《Java多线程编程-(8)-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier》 这一篇中,我们使用线程计数器的方式实现了...

    Java后端技术
  • Flutter异步编程

    经常听说 future,或者从其他语言见到类似的说法如 javascript 的 Promise。那么究竟什么是 future?

    ChildhoodAndy
  • 从源码出发浅析 Android TV 的焦点移动原理(下篇)

    焦点(Focus)可以理解为选中态,在 Android TV上起很重要的作用。一个视图控件只有在获得焦点的状态下,才能响应按键的 Click 事件。

    QQ音乐技术团队
  • HDU-2017 ACM/ICPC Asia Regional Qingdao Online-1011-A Cubic number and A Cubic Number

    ACM模版 描述 ? 题解 上 oeisoeis 可以查到这个 YESYES 的数列,这个数列的每一项都是素数,并且可以化成如下: image.png 所以最...

    f_zyj

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动