Dart异步模型

我的梦境 提交于 2019-12-28 01:46:48

Dart汇总请点击这里

同步代码和异步代码;

同步代码:就是一行行写下来的代码
异步代码:就是以Future等修饰的代码

这两类代码的不同

1.运行顺序不同

同步代码和异步代码运行的顺序是不同的:
先运行同步代码,在运行异步代码
复制代码就是,即使我异步代码写在最前面,同步代码写在最后面,我也是先运行后面的同步代码,同步代码都运行完后,在运行前面的异步代码。
一下代码的输出结果是什么?

import 'dart:async';
main() {
  print('main #1 of 2');
  scheduleMicrotask(() => print('microtask #1 of 2'));

  new Future.delayed(new Duration(seconds:1),
                     () => print('future #1 (delayed)'));
  new Future(() => print('future #2 of 3'));
  new Future(() => print('future #3 of 3'));

  scheduleMicrotask(() => print('microtask #2 of 2'));

  print('main #2 of 2');
}
main #1 of 2
main #2 of 2
microtask #1 of 2
microtask #2 of 2
future #2 of 3
future #3 of 3
future #1 (delayed)

2.运行的机制不同

异步代码是运行在event loop里的,event loop不断的从事件队列里取事件然后运行。

Dart 的事件循环

Dart 是事件驱动的体系结构,该结构基于具有单个事件循环两个队列的单线程执行模型。 Dart虽然提供调用堆栈。 但是它使用事件在生产者和消费者之间传输上下文。 事件循环由单个线程支持,因此根本不需要同步和锁定。

Dart 的两个队列

  • MicroTask queue 微任务队列
  • Event queue 事件队列

在这里插入图片描述
Dart事件循环执行如上图所示

  1. 先查看MicroTask队列是否为空,不是则先执行MicroTask队列
  2. 一个MicroTask执行完后,检查有没有下一个MicroTask,直到MicroTask队列为空,才去执行Event队列
  3. 在Evnet 队列取出一个事件处理完后,再次返回第一步,去检查MicroTask队列是否为空

注意:我们可以看出,将任务加入到MicroTask中可以被尽快执行,但也需要注意,当事件循环在处理MicroTask队列时,Event队列会被卡住,应用程序无法处理鼠标单击、I/O消息等等事件。

控制任务调度

将任务添加到MicroTask队列有两种方法

  1. 使用 scheduleMicrotask 方法添加
  2. 使用Future对象添加
import  'dart:async';
//我的任务队列
void  myTask(){
    print("this is my task");
}

void  main() {
    # 1. 使用 scheduleMicrotask 方法添加
    scheduleMicrotask(myTask);

    # 2. 使用Future对象添加
    new  Future.microtask(myTask);
}

将任务添加到Event队列

使用Future对象添加

import  'dart:async';
//我的任务
void  myTask(){
    print("this is my task");
}

void  main() {
 # 1. 使用Future对象添加
  new Future(myTask); 
}

验证

import 'dart:async'

void main() {

  print('main Start');

  new Future((){
    print('this is my task');
  });

  new Future.microtask((){
    print('this is microtask');
  });

  print('main Stop');
  
}
main start
main stop
this is microtask
this is my task

可以看到,代码的运行顺序并不是按照我们的编写顺序来的,将任务添加到队列并不等于立刻执行,它们是异步执行的,当前main方法中的代码执行完之后,才会去执行队列中的任务,且MicroTask队列运行在Event队列之前。

延时任务

如需要将任务延伸执行,则可使用Future.delayed方法

new  Future.delayed(new  Duration(seconds:1),(){
    print('task delayed');
});

表示在延迟时间到了之后将任务加入到Event队列。需要注意的是,这并不是准确的,万一前面有很耗时的任务,那么你的延迟任务不一定能准时运行。

import  'dart:async';
import  'dart:io';

void  main() {
    print("main start");

    new Future.delayed(new  Duration(seconds:1),(){
        print('task delayed');
    });

    new Future((){
        // 模拟耗时5秒
        sleep(Duration(seconds:5));
        print("5s task");
    });

    print("main stop");
}

运行结果:

main start
main stop
5s task
task delayed

从结果可以看出,delayed方法调用在前面,但是它显然并未直接将任务加入Event队列,而是需要等待1秒之后才会去将任务加入,但在这1秒之间,后面的new Future代码直接将一个耗时任务加入到了Event队列,这就直接导致写在前面的delayed任务在1秒后只能被加入到耗时任务之后,只有当前面耗时任务完成后,它才有机会得到执行。这种机制使得延迟任务变得不太可靠,你无法确定延迟任务到底在延迟多久之后被执行。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!