Flutter 事件机制 - Future 和 MicroTas

作者: 06fd4cf1f427 | 来源:发表于2019-04-10 22:25 被阅读4次

    写在前面

    了解过Flutter的同学都知道,不同于 Android 原生开发,dart 是单线程实体的语言,所以我们一般的异步操作,实际上还是通过单线程通过调度任务优先级来实现的,就是我们经常用到的 Future,但是Flutter中的事件机制究竟是怎样的?多个Future 和 Microtask 程序的执行顺序是怎样的? 本文将借助两个比较复杂的例子来详细介绍 Flutter 的事件机制,希望能对大家有所帮助。

    Main代码块,EventQueue,MicrotaskQueue 的执行优先级

    首先我得提一嘴 isolate(隔离),isolate是有自己的内存和单线程控制的运行实体,isolate类似于线程。 运行中的 Flutter 程序由一个或多个 isolate 组成。我们的代码默认都在 Main isolate中执行。
    为了保持高的响应性,特别耗时的任务一般不要放在Main isolate 中。但 isolate 不是本文的重点,在此就不过多赘述。

    Dart 中事件机制的实现 :Main isolate 中有一个Looper,但存在两个Queue:Event Queue 和 Microtask Queue 。
    因为 isolate 是单线程实体,所以 isolate中的代码是按顺序执行的。
    所以 dart 中的代码执行优先级可以分为三个级别:

    1. 在 Main 中写代码将最先执行;
    2. 执行完 Main 中的代码,然后会检查并执行 Microtask Queue 中的任务, 通常使用 scheduleMicrotask 将事件添加到 MicroTask Queue 中;
    3. 最后执行 EventQueue 队列中的代码,通常使用 Future 向 EventQueue加入时间,也可以使用 async 和 await 向 EventQueue 加入事件。

    总结:Dart 中事件的执行顺序:Main > MicroTask > EventQueue。
    如图:

    image.png

    验证:

    void testSX(){
      new Future(() => print('s_1'));
      scheduleMicrotask(() => print('s_2'));
      print('s_3');
    }
    

    输出结果:

    I/flutter (32415): s_3
    I/flutter (32415): s_2
    I/flutter (32415): s_1
    

    Future简介

    前面讲到,用 async 和 await 组合,即可向 event queue 中插入 event 实现异步操作,那为什么还会有Future呢?
    其实,Future 最主要的功能就是提供了链式调用。

    new Future (() => print('拆分任务_1'))
        .then((i) => print('拆分任务_2'))
        .then((i) => print('拆分任务_3'))
        .whenComplete(()=>print('任务完成'));
    

    Future中的 then 并没有创建新的Event丢到Event Queue中,而只是一个普通的Function,在一个 Future 所有的 Function 执行完后,下一个 Future 才会开始执行。

    多个 Future 的执行顺序

    1. 规则一:Future 的执行顺序为Future的在 EventQueue 的排列顺序。类似于 JAVA 中的队列,先来先执行。
    2. 规则二:当任务需要延迟执行时,可以使用 new Future.delay() 来将任务延迟执行。
    3. 规则三: Future 如果执行完才添加 than ,该任务会被放入 microTask,当前 Future 执行完会执行 microTask,microTask 为空后才会执行下一个Future。
    4. 规则四:Future 是链式调用,意味着Future 的 then 未执行完,下一个then 不会执行。

    理论结束,然后来看一段代码吧:

    void testFuture() {
      Future f1 = new Future(() => print('f1'));
      Future f2 = new Future(() =>  null);
      Future f3 = new Future.delayed(Duration(seconds: 1) ,() => print('f2'));
      Future f4 = new Future(() => null);
      Future f5 = new Future(() => null);
    
      f5.then((_) => print('f3'));
      f4.then((_) {
        print('f4');
        new Future(() => print('f5'));
        f2.then((_) {
          print('f6');
        });
      });
      f2.then((m) {
        print('f7');
      });
      print('f8');
    }
    

    各位同学可以试着写一下结果,然后对比下输出结果。

    输出结果:

    com.example.flutter_dart_app I/flutter: f8
    com.example.flutter_dart_app I/flutter: f1
    com.example.flutter_dart_app I/flutter: f7
    com.example.flutter_dart_app I/flutter: f4
    com.example.flutter_dart_app I/flutter: f6
    com.example.flutter_dart_app I/flutter: f3
    com.example.flutter_dart_app I/flutter: f5
    com.example.flutter_dart_app I/flutter: f2
    

    是不是跟自己的结果大相径庭,别急,看我来慢慢分析: 分析:

    1. 首先执行Main 的代码,所以首先输出: 8;
    2. 然后参考上面的规则1,Future 1 到 5 是按初始化顺序放入 EventQueue中,所以依次执行Future 1到5 , 所以输出结果:8,1,7。
    3. 参考规则2,f3 延时执行,一定是在最后一个:8,1,7,…,2。
    4. 在 f4 中,首先输出 f4 :8,1,7,4,…,2。
    5. 在 f4 的 then 的方法块中,新建了Future, 所以新建的 Future 将在 EventQueue尾部,最后被执行:8,1,7,4,…,5,2。
    6. 在 f4 的 then 的方法块中,给 f2 添加了 then ,但此时 f2 已经执行完了,参考规则三,所以 then 中的代码会被放到 microTask 中,在当前 Future 执行完后执行。 因为此时Future f4已经执行完了,所以会处理microTask(microTask优先级高)。结果:8,1,7,4,6,..,5,2。
    7. 此时我们的 EventQueue 中还有 f5,和在 f4 中添加的新的Future。 所以我们的最终结果就是:8,1,7,4,6,3,5,2。

    是不是有点理解不了,没事,牢记四个规则,自己再算一遍,相信你就了然于胸了。重要要在脑海里有一个 EventQueue 的队列模型,牢记先进先出。

    然后来试一试下一题:

    多Future 和 多micTask 的执行顺序

    void testScheduleMicrotatsk() {
      scheduleMicrotask(() => print('Mission_1'));
    
    //注释1
      new Future.delayed(new Duration(seconds: 1), () => print('Mission_2'));
    
    //注释2
      new Future(() => print('Mission_3')).then((_) {
        print('Mission_4');
        scheduleMicrotask(() => print('Mission_5'));
      }).then((_) => print('Mission_6'));
    
    //注释3
      new Future(() => print('Mission_7'))
          .then((_) => new Future(() => print('Mission_8')))
          .then((_) => print('Mission_9'));
    
    //注释4
      new Future(() => print('Mission_10'));
    
      scheduleMicrotask(() => print('Mission_11'));
    
      print('Mission_12');
    }
    
    

    大家可以先自己试一下,再对照结果~

    输出结果:

    I/flutter (19025): Mission_12
    I/flutter (19025): Mission_1
    I/flutter (19025): Mission_11
    I/flutter (19025): Mission_3
    I/flutter (19025): Mission_4
    I/flutter (19025): Mission_6
    I/flutter (19025): Mission_5
    I/flutter (19025): Mission_7
    I/flutter (19025): Mission_10
    I/flutter (19025): Mission_8
    I/flutter (19025): Mission_9
    Syncing files to device MIX 3...
    I/flutter (19025): Mission_2
    

    是不是还是没答全对?没关系,很正常,看我慢慢道来:
    分析:

    1. 根据 Main > MicroTask > EventQueue。我们首先会得到输出结果:12,1,11。
    2. 注释1 的 Future 是延时执行,所以:12,1,11,…,2。
    3. 注释2 中创建了 Microtask,Microtask会在该Future执行完后执行,所以:12,1,11,4,6,5,…,2。
    4. 重点来了。我们在注释3 的Future 的 then 中新建了Future(输出Mission_8),新建的 Future 将被加到 EventQueue尾部,并且,注释3的Future后续的then将不再执行,因为这个链被阻塞了!
      注意对比上一题中的 f4, 上一题中的 f4 是一个 than 方法包裹了代码块。
      此时的结果:12,1,11,4,6,5,7,…,2。
    5. 执行完注释4 的 Future,然后会执行我们在注释3 Future 新加入的 Future,之后注释3 的Future不再阻塞,会继续执行,结果: 12,1,11,4,6,5,7,10,8,9,2。

    看到这里,相信各位同学已经对 Dart 事件机制有一个大概的了解,希望能对 各位在学Flutter 的同学有所帮助,蟹蟹~

    END

    【附】相关架构及资料

    加群 Android IOC架构设计领取获取往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

    image

    领取方式:

    点赞+加群免费获取 Android IOC架构设计

    相关文章

      网友评论

        本文标题:Flutter 事件机制 - Future 和 MicroTas

        本文链接:https://www.haomeiwen.com/subject/susaiqtx.html