Dart中的异步编程(Future、scheduleMicrotask)

Dart是一门单线程的语言,Dart对异步操作对支持,可以使我们在编写Dart程序时可以异步的来执行耗时操作。这里的异步和多线程不是一个概念,在Dart中,异步但没有多线程,仍然是单线程。

Dart的事件循环(event loop)

在Dart中,实际上有两种队列:

  1. 事件队列(event queue),包含所有的外来事件:I/O、mouse events、drawing events、timers、isolate之间的信息传递。
  2. 微任务队列(microtask queue),表示一个短时间内就会完成的异步任务。它的优先级最高,高于event queue,只要队列中还有任务,就可以一直霸占着事件循环。microtask queue添加的任务主要是由 Dart内部产生。

因为 microtask queue 的优先级高于 event queue ,所以如果 microtask queue有太多的微任务, 那么就可能会霸占住当前的event loop。从而对event queue中的触摸、绘制等外部事件造成阻塞卡顿。

在每一次事件循环中,Dart总是先去第一个microtask queue中查询是否有可执行的任务,如果没有,才会处理后续的event queue的流程。


image.png

异步任务我们用的最多的还是优先级更低的 event queue。Dart为 event queue 的任务建立提供了一层封装,就是我们在Dart中经常用到的Future。

正常情况下,一个 Future 异步任务的执行是相对简单的:

  1. 声明一个 Future 时,Dart 会将异步任务的函数执行体放入event queue,然后立即返回,后续的代码继续同步执行。
  2. 当同步执行的代码执行完毕后,event queue会按照加入event queue的顺序(即声明顺序),依次取出事件,最后同步执行 Future 的函数体及后续的操作。
通过代码来看一下Future这个异步编程是啥样的(showCode)
void test1() {
  String a = 'A';
  print('最开始:$a');
  for (int i = 0; i < 10000000000; i++) {
    a = '网络请求';
  }

  print('结束:$a');
}

void test2() {
  String a = 'A';
  print('最开始a=:$a');
  Future(() {
    // 这里的耗时操作放到异步操作里去。  Future里的内容就是异步操作的
    for (int i = 0; i < 10000000000; i++) {
      a = '网络请求';
    }
    print('耗时操作最后a=:$a');
  });

  print('结束a=:$a');
}

void test3() async {
  // async和await要配套使用
  String a = 'A';
  print('最开始a=$a');
  await Future(() {
    // 通过await去修饰,那么主线程会等Future的异步操作结束后再继续往下走。
    for (int i = 0; i < 10000000000; i++) {
      a = '网络请求';
    }
  });
  print('结束a=$a');
}

void test4() {
  String a = 'A';
  print('最开始a=$a');
  Future future = Future(() {
    // Future通过返回一个Future对象可以来操作then,达到和test3一样的效果。
    for (int i = 0; i < 1000000000; i++) {
      a = '网络请求';
    }
    print('耗时操作里面的a=$a');
    return a;
  });

  future.then((onValue) {
    print('then里面的a=$a');
  });
}

void test5() {
  String a = 'A';
  print('最开始a=$a');
  Future(() {
    // Future通过链式调用的方式,推荐用这种方式。把需要在耗时操作后面执行的内容放到then里面去。
    // then里面的内容一样是异步。
    for (int i = 0; i < 1000000000; i++) {
      a = '网络请求';
    }
    print('耗时操作里面的a=$a');
    return a;
  }).then((onValue) {
    print('then里面的a=$a');
  });
}

void test6() {
  // 多个Future存在的时候,顺序是怎样的呢?

  print('主线程同步开始');

  Future(() {
    print('任务1开始');
    return '任务1';
  }).then((value) => print('$value结束了'));

  Future(() {
    print('任务2开始');
    return '任务2';
  }).then((value) => print('$value结束了'));

  Future(() {
    print('任务3开始');
    return '任务3';
  }).then((value) => print('$value结束了'));

  Future(() {
    print('任务4开始');
    return '任务4';
  }).then((value) => print('$value结束了'));

  Future(() {
    print('任务5开始');
    return '任务5';
  }).then((value) => print('$value结束了'));

  print('主线程同步结束');
}

void test61() {
  // Future 数组  多个Future还可以用数组的形式来表达

  Future.wait([
    Future(() {
      return '任务1';
    }),
    Future(() {
      return '任务2';
    }),
  ]).then((value) => print('任务执行结果为:${value[0]} 以及 ${value[1]}'));

  // 此时then里的内容会等Future数组里的2个异步任务都执行完毕了再执行。
}

void test7() {
  // 多个Future中还存在microtask(微任务)的时候,执行顺序又是如何

  print('主线程同步开始');

  /*
    1、Future的异步事件是按Future声明的顺序放入的event loop里的,then里的异步操作是放到微任务microtask loop 里面的。
    2、microtask loop队列里的异步事件的执行优先级比event loop异步队列里的优先级高
    3、每个loop time的时候都会先去microtask loop队列里看看当前是否有microtask未执行,有的话,优先执行microtask。
  */
  Future(() {
    print('任务1开始');
    scheduleMicrotask(() {
      // 这个microtask比then要晚执行,是因为他比then要晚放到microtask队列里。 then是在当前的Future申明的时候就放进去了,而这个
      // microtast 是Future执行的时候才放进去的,所以比then要晚。  注 then虽然可以理解是放到microtask队列里,但是它只有当前的Future执行完才会执行的。
      print('任务1里的微任务1开始');
    });
    return '任务1';
  }).then((value) => print('$value结束了'));

  Future(() {
    print('任务2开始');
    scheduleMicrotask(() {
      print('任务2里的微任务1开始');
    });
    return '任务2';
  }).then((value) => print('$value结束了'));

  Future(() {
    print('任务3开始');
    scheduleMicrotask(() {
      print('任务3里的微任务1开始');
    });
    return '任务3';
  }).then((value) => print('$value结束了'));

  Future(() {
    print('任务4开始');
    scheduleMicrotask(() {
      print('任务4里的微任务1开始');
    });
    return '任务4';
  }).then((value) => print('$value结束了'));

  Future(() {
    print('任务5开始');
    scheduleMicrotask(() {
      print('任务5里的微任务1开始');
    });
    return '任务5';
  }).then((value) => print('$value结束了'));

  scheduleMicrotask(() {
    print('这是微任务');
  });

  print('主线程同步结束');
}

void test8() {
  // 猜猜看,执行顺序是啥。。。
  Future x1 = Future(() => null);
  Future x = Future(() => print('1'));
  Future(() => print('2'));
  scheduleMicrotask(() => print('3'));
  x.then((value) => print('4'));
  print('5');
  x1.then((value) => print('6'));

  // 答案是:5、3、6、1、4、2
}

void test9() {
  // 猜猜看,执行顺序是啥。。。
  Future x1 = Future(() => null);
  x1.then((value) {
    print('6');
    scheduleMicrotask(() => print('7'));
  }).then((value) => print('8'));
  Future x = Future(() => print('1'));
  Future(() => print('2'));
  scheduleMicrotask(() => print('3'));
  x.then((value) => print('4'));
  print('5');

  // 答案是:5、3、6、8、7 、1、4、2
}

void test10() {
  //flutter的多线程 Isolate  执行顺序是无序的,且变量和外部的变量是隔离的。即便同名变量也是2个不同的变量
  // 好处是不用担心多线程访问对资源的抢夺。
  Isolate.spawn(fun11, 100);
  Isolate.spawn(fun12, 200);
  Isolate.spawn(fun11, 100);
  Isolate.spawn(fun12, 200);
  Isolate.spawn(fun11, 100);
  Isolate.spawn(fun12, 200);
  Isolate.spawn(fun11, 100);
  Isolate.spawn(fun12, 200);
  Isolate.spawn(fun11, 100);
  Isolate.spawn(fun12, 200);
  Isolate.spawn(fun13, {'name': '112'});
}

void fun11(int count) {
  print('fun11--$count');
}

void fun13(Map count) {
  print('fun11--$count');
}

void fun12(int count) {
  print('fun12--$count');
}

void test12() {
  print('函数主线程开始');
  // compute是一个多线程。
  compute(fun14, {'name': '112'}).then((value) => print(value));
  print('函数主线程结束');
}

Map fun14(Map count) {
  print('fun11--$count');
  return count;
}

参考引用了文章 Dart中的异步编程——Future、async和await

你可能感兴趣的:(Dart中的异步编程(Future、scheduleMicrotask))