美文网首页
Dart 异步(一)线程

Dart 异步(一)线程

作者: 陆元伟 | 来源:发表于2023-01-08 17:43 被阅读0次

单线程事件队列

Dart程序是单线程+事件驱动方式运行,Dart代码的运行就是在不停的在处理一个又一个的事件
而 Dart 的单线程跟 Java 的完全不同,虽然都是单线程,但是 Dart 分为三个形式:

主线程
微任务队列
事件任务队列

主线程

跟 Java 一样,具有唯一性,也就是从main()开始的线程。

微任务队列

表示一个短时间内就会完成的异步任务,它的优先级比事件队列高。
主要是通过scheduleMicrotask进行调度。

事件任务队列

包含所有的外来事件,比如:I/O、手势、绘图等。,例如:I/O 事件任务、Timer 事件任务等。

Flutter 任务队列的执行图:


图片.png

优先级

1 主线程 > 微任务队列 > 事件任务队列。

所以,在 Dart 单线程中,会优先执行完主线程,在执行主线程的过程中,若发现微任务或者事件任务,就会将他们放入相应的任务队列中,然后就会一个个执行完微任务队列里面的微任务,其次再去执行事件任务队列里面的事件任务。

示例代码如下

     Timer.run(() {
       print('Timer run');
     });
     scheduleMicrotask(() {
       print('scheduleMicrotask run');
     });
      print('main run');

打印输出,可以看出,即使我们把事件任务队列放在最前面,它也是最后执行

main run
scheduleMicrotask run
Timer run

Process finished with exit code 0

再来个复杂例子,在事件任务里面添加微任务,在微任务里面添加事件任务

 //主线程
    print('main start!');
    //事件任务
    Timer.run(() {
      print('事件任务 start!');
      //子微任务
      scheduleMicrotask(() {
        print('子微任务执行!');
      });
      print('事件任务 end!');
    });
    //微任务
    scheduleMicrotask(() {
      print('微任务 start!');
      //子事件任务
      Timer.run(() {
        print('微任务中子事件任务执行!');
      });
      scheduleMicrotask((){
        print('微任务微子事件任务执行!');
      });
      print('微任务 end!');
    });
    print('main end!');

输出

main start!
main end!
微任务 start!
微任务 end!
微任务微子事件任务执行!
事件任务 start!
事件任务 end!
子微任务执行!
微任务中子事件任务执行!

首先是main任务执行完,然后再执行微任务,等微任务完成后,再执行事件任务,等事件任务执行完,再微任务,事件任务。

添加sleep延迟

  //主线程
      print('main start!');
      sleep(Duration(seconds: 2));
      //微任务
      scheduleMicrotask((){
        print('微任务 start!');
        sleep(Duration(seconds: 2));
        //子事件任务
        Timer.run(() {
          print('子事件任务执行!');
          sleep(Duration(seconds: 2));
        });
        print('微任务 end!');
      });
      //事件任务
      Timer.run(() {
        print('事件任务 start!');
        sleep(Duration(seconds: 2));
        //子微任务
        scheduleMicrotask((){
          print('子微任务执行!');
          sleep(Duration(seconds: 2));
        });
        print('事件任务 end!');
      });
      print('main end!');

输出如下,由于dart本来就是单线程,,隐藏sleep后,后面的任务都暂停了,因此任务顺序不变

main start!
main end!
微任务 start!
微任务 end!
事件任务 start!
事件任务 end!
子微任务执行!
子事件任务执行!

结论: 在 Dart 单线程中,主线程、微任务队列、事件任务队列是线性执行的,后面的队列必须等到前面队列都运行完后再执行

多线程

在一个页面中做耗时比较大的运算时,就算用了 async、await 异步处理,UI页面的动画还是会卡顿,因为还是在这个UI线程中做运算,异步只是你可以先做其他,等我这边有结果再返回,但是,我们的计算仍旧是在这个UI线程,仍会阻塞UI的刷新,异步只是在同一个线程的并发操作。所以这个时候就需要创建新的线程来执行耗时操作解决这个问题。

什么是 Isolate

Isolate 是 Dart 平台对线程的实现方案,但和普通 Thread 不同的是,isolate 拥有独立的内存,isolate 由线程和独立内存构成。正是由于 isolate 线程之间的内存不共享,所以 isolate 线程之间并不存在资源抢夺的问题,所以也不需要锁。通过 isolate 可以很好的利用多核 CPU,来进行大量耗时任务的处理。

print('main start');
    Isolate.spawn((msg){
      print('spawn 1');
      print(msg);
    },'1');
    Isolate.spawn((msg){
      print('spawn 2');
      print(msg);
    },'2');
    Isolate.spawn((msg){
      print('spawn 3');
      print(msg);
    },'3');
    print('main end');

输出如下(每次输出不一样)

main start
spawn 1
1
main end
spawn 3
3
spawn 2
2

Isolate 通信机制

isolate 之间的通信主要通过 SendPort和ReceivePort来进行。主要流程是:先初始化一个ReceivePort,然后调用listen就可以监听其他isolate发送的消息。
那其他isolate如何给当前isolate发送消息?答案就是获取到ReceivePort的sendPort。

ReceivePort:接收其他Isolate数据
SendPort:发送给其他Isolate数据

代码如下,由于生成Isolate的spawn方法第二个参数就是传递给Isolate的数据,因此我们把主isolate的SendPort发送过去,这样子isolate获取到主Isolate的SendPort,就可以调用sendPort的send方法给主Isolate发送数据,主Isolate就可以接收到。

那主Isolate除了创建时给子Isolate发送数据,后续如何给子Isolate继续发送数据呢?

这就要求子Isolate把它自己的SendPort发送给主Isolate

    print('main start');
    ReceivePort port = ReceivePort();
     Isolate iso = await Isolate.spawn<SendPort>((message) {
      print('子iso:发送消息gaga');
      message.send('gaga');
      print('子iso:发送成功');

      ReceivePort iosPort = ReceivePort();
      message.send(iosPort.sendPort);
      iosPort.listen((msg) {
        print('子iso:$msg');
      });
      print('子iso:发送port成功');
    }, port.sendPort);

    port.listen((message) {
      print('主iso:收到子iso $message');
      if(message is SendPort){
        message.send('主线程发送子线程消息');
        port.close();
      }
    });
 print('main end');

输出如下

main start
main end
子iso:发送消息gaga
子iso:发送成功
子iso:发送port成功
主iso:收到子iso gaga
主iso:收到子iso SendPort
子iso:主线程发送子线程消息

参考文章:
Dart单线程理解(与Java完全不同)
Flutter异步编程-Isolate
深入理解Flutter/Dart事件机制

相关文章

  • Day04-Dart-基础语法三:异步

    概述 Dart的异步模型 Dart的异步操作 Dart的异步补充 一、Dart的异步模型 1.1、Dart是单线程...

  • 401--Flutter for iOS 3--线程和异步

    线程和异步 1. 我怎么编写异步的代码? Dart 是单线程执行模型,但是它支持 Isolate(一种让 Dart...

  • dart异步编程

    dart是单线程 一定要记得很清楚dart异步不同于java的线程,java线程是抢占式,但dart相当于开辟...

  • Flutter(三)Dart的异步

    一. Dart的异步模型 我们先来搞清楚Dart是如何搞定异步操作的 1.1. Dart是单线程的 1.1.1. ...

  • Dart的”多线程“

    Dart的”多线程“ 众所周知,Dart是一门单线程的语言,我们可以将一些需要等待的任务放到异步操作中,但是异步任...

  • [Flutter] 05-Dart中事件循环

    一、Dart的异步模型 我们先来看一下Dart是如何进行异步操作的 1、Dart是单线程的 1.1)、 程序中的耗...

  • Dart中的异步编程(Future、scheduleMicrot

    Dart是一门单线程的语言,Dart对异步操作对支持,可以使我们在编写Dart程序时可以异步的来执行耗时操作。这里...

  • Dart 异步(一)线程

    单线程事件队列 Dart程序是单线程+事件驱动方式运行,Dart代码的运行就是在不停的在处理一个又一个的事件而 D...

  • 搞懂Dart异步并封装Isolate

    Dart 是单线程,那么怎么异步呢?或者耗时为什么不卡线程呢? Dart 代码运行在单个执行线程中,Flutter...

  • Dart中的异步操作

    1. Dart中的异步模型 我们需要搞清楚Dart是如何搞定异步操作的。首先,Dart是单线程的。 在之前的开发中...

网友评论

      本文标题:Dart 异步(一)线程

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