美文网首页
Flutter开发进阶:Flutter事件循环机制与异步

Flutter开发进阶:Flutter事件循环机制与异步

作者: __Null | 来源:发表于2022-03-17 08:10 被阅读0次

    Dart是基于 事件循环机制的单线程模型, 所以Dart中没有多线程, 也就没有主线程与子线程之分。

    • 单线程模型:一条执行线上同时只能执行一个任务,如果有耗时任务则需要放入队列异步执行。
    • 多线程:充分利用处理器的多核优势进行并行计算。

    一、事件循环机制

    对于用户点击, 滑动, 硬盘IO访问等事件, 你不知道何时发生或以什么顺序发生, 所以得有一个永不停歇且不能阻塞的循环来等待处理这些 "突发" 事件. 于是, 基于 事件循环机制 的 单线程模型 就出现了。

    Dart的事件循环机制由一个消息循环(Event Looper)和两个消息队列构成。两个消息队列分别是事件队列(Event Queue)和微任务队列(Microtask Queue)。

    1.Event Looper

    Dart在执行完main函数后, Event Looper就开始工作, Event Looper优先全部执行完 Microtask Queue中的event, 直到Microtask Queue为空时, 才会执行Event Looper中的 event, Event Looper为空时才可以退出循环。

    2.Event Queue
    • Event Queue的 event 来源于外部事件或Future
    • 外部事件:例如输入/输出, 手势, 绘制, 计时器, Stream等,
    • Future:用于自定义Event Queue事件。

    对于外部事件, 一旦没有任何 microtask 要执行, Event loop 才会考虑 event queue 中的第一项, 并且将会执行它。

    • 案例:向Event Queue中添加事件任务
    Future(() {
      // 事件任务
    });
    
    3.Microtask Queue
    • Microtask Queue的优先级高于Event Queue.
    • 使用场景: 想要在稍后完成一些任务(microtask) 但又希望在执行下一个事件(event)之前执行.

    Microtask 一般用于非常短的内部异步动作, 并且任务量非常少, 如果微任务非常多, 就会造成 Event Queue 排不上队, 会阻塞 Event Queue 的执行(如: 用户点击没有反应). 所以, 大多数情况下优先考虑使用 Event Queue, 整个 Flutter 源代码仅引用 scheduleMicroTask() 方法 7 次.

    • 案例:向 Microtask Queue 添加微任务:
    scheduleMicrotask(() {
      // 微任务
    });
    

    二、Future

    1. Future 实例有 3 个常用方法:
    • then((value){...}): 正常运行时执行
    • catchError((err){...}): 出现错误时执行
    • whenComplete((){...}): 不管成功与否都会执行
    2.链式调用

    Future 可以在 then()方法中返回另一个 Future 实例, 从而达到链式调用的效果, 这对那些有数据关联的网络请求很有用

    3.其他

    Future 除了默认构造器外, 还提供了几个常用的命名构造器:

    • Future.value(): 创建一个返回具体数据的 Future 实例
    • Future.error(): 创建一个返回错误的 Future 实例
    • Future.delayed(): 创建一个延时执行的 Future 实例

    三、async/await

    1、基本使用

    • await 必须在 async 函数中使用
    • async 函数返回的结果必须是一个 Future

    四、isolate

    所有的 Dart 代码都是在 isolate 中运行的, 它就是机器上的一个小空间, 具有自己的私有内存块和一个运行着 Event Looper 的单个线程. 每个 isolate 都是相互隔离的, 并不像线程那样可以共享内存. 一般情况下, 一个 Dart 应用只会在一个 isolate 中运行所有代码, 但如果有特殊需要, 可以开启多个:

    1、创建 isolate (Dart API)

    Dart 默认提供了 Isolate.spawn(entryPoint, message) 用于开启 isolate, 通过源码可以知道形参 message 其实是 形参 entryPoint 对应的函数执行时需要的参数。
    使用 Isolate.spawn(entryPoint, message) 开启 isolate, 并指定要执行的任务:

    import 'dart:isolate';
    main(List<String> args) {
      print("main start");
      Isolate.spawn(calc, 100);
      print("main end");
    }
    
    void calc(int count) {
      var total = 0;
      for (var i = 0; i < count; i++) {
        total += i;
      }
      print(total);
    }
    
    2、isolate 通信 (单向)

    isolate 间可以一起工作的唯一方法是通过来回传递消息. 一般情况下, 子isolate 会将运行结果通过管道以消息的形式发送到 主isolate, 并在 主isolate 的 Event Looper 中处理该消息, 这时就需要借助 ReceivePort 来处理消息的传递了:

    • 在启动 子isolate 时, 将 主isolate 的发送管道(SendPort)作为参数传递给 子isolate.
    • 子isolate 在执行完毕时, 可以利用管道(SendPort)给 主isolate 发送信息.
    import 'dart:isolate';
    main(List<String> args) async {
      print("main start");
    
      // 1. 创建管道
      var receivePort = ReceivePort();
    
      // 2. 创建isolate
      Isolate isolate = await Isolate.spawn(foo, receivePort.sendPort);
    
      // 3. 监听管道
      receivePort.listen((message) {
        print(message);
        // 不再使用时, 关闭管道
        receivePort.close();
        // 不再使用时, 将 isolate 杀死
        isolate.kill();
      });
    
      print("main end");
    }
    
    void foo(SendPort sendPort) {
      sendPort.send("Hello lqr");
    }
    
    3、创建 isolate (Flutter API)

    Flutter 提供了更为方便的开启 isolate 的 API: compute() 函数. 以下是示例代码:

    main(List<String> args) async {
      int result = await compute(powerNum, 5);
      print(result);
    }
    
    int powerNum(int num) {
      return num * num;
    }
    

    相关文章

      网友评论

          本文标题:Flutter开发进阶:Flutter事件循环机制与异步

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