Dart事件循环机制

简介: Dart事件循环机制

什么是事件循环?

Dart 是单线程的,这意味着 Dart 代码是按照在 main出现的次序,一个接一个地执行的,不会被其他代码中断。

Dart 也支持异步,单线程和异步并不冲突。

为什么单线程也可以异步?这里有一个大前提,那就是我们的 App 绝大多数时间都在等待,而这些等待行为并不是阻塞的。

为什么单线程也可以异步?这里有一个大前提,那就是我们的 App 绝大多数时间都在等待,而这些等待行为并不是阻塞的。所以,基于这些特点,单线程模型可以在等待的过程中做别的事情,等真正需要响应结果了,再去做对应的处理,因为等待过程并不是阻塞的,所以给我们的感觉就像是同时在做多件事情一样,但其实始终只有一个线程在处理你的事情。等待这个行为是通过 Event Loop 驱动的。事件队列 Event Queue 会把其他平行世界完成的,需要主线程响应的事件放入其中。像其他语言一样,Dart 也有一个巨大的事件循环,在不断的轮循事件队列、取出事件(比如键盘事件、I\O 事件、网络事件等),在主线程同步执行其回调函数。


微任务队列

在 Dart 中,实际上有两个队列,一个是事件队列(Event Queue),另一个则是微任务队列(Microtask Queue)。

微任务队列,顾名思义,表示一个短时间内就会完成的异步任务。微任务队列在事件循环中的优先级是最高的,在每一次事件循环中,Dart 总是先去微任务队列中查询是否有可执行的任务,如果没有,才会处理后续的事件队列的流程

所以,Dart 中 Event Loop 完整版的流程图,应该如下所示:

一般的异步任务通常很少必须要在事件队列前完成,因此很少会使用微任务队列。Flutter 内部,也只有 7 处需要高优执行任务的场景用到了而已。而像 I/O、绘制、定时器这些异步事件,都是通过事件队列驱动主线程执行的。

事件队列包含外部事件,例如I/O, Timer,绘制事件,Future(部分情况)等等。

微任务队列则包含有Dart内部的微任务,主要是通过scheduleMicrotask,Future(部分情况)来调度。

事件与微任务队列

微任务与事件队列调用关系

void call() {
  Logger("start");
  Future(() => "Future").then((value) => Logger(value));
  scheduleMicrotask(() {
    Logger("microTask1");
    scheduleMicrotask(() {
      Logger("microTask2");
    });
  });
  Logger("end");
}
void Logger(Object obj) {
  print("${DateTime.now()} - $obj");
}

运行结果

flutter: 2023-03-20 17:10:28.289542 - start
flutter: 2023-03-20 17:10:28.297768 - end
flutter: 2023-03-20 17:10:28.369215 - microTask1
flutter: 2023-03-20 17:10:28.369964 - microTask2
flutter: 2023-03-20 17:10:28.376639 - Future

更复杂的情况

void call() {
  Logger("start");
  Future(() => "Future1").then((value) => Logger(value));
  scheduleMicrotask(() {
    Logger("microTask1");
    scheduleMicrotask(() {
      Logger("microTask2");
    });
  });
  Future(() => "Future2").then((value) => Logger(value));
  scheduleMicrotask(() {
    Logger("microTask3");
  });
  Logger("end");
}

运行结果

flutter: 2023-03-20 17:15:56.098555 - start
flutter: 2023-03-20 17:15:56.106995 - end
flutter: 2023-03-20 17:15:56.180110 - microTask1
flutter: 2023-03-20 17:15:56.180359 - microTask3
flutter: 2023-03-20 17:15:56.180983 - microTask2
flutter: 2023-03-20 17:15:56.187536 - Future1
flutter: 2023-03-20 17:15:56.188171 - Future2

符合上述预期的结果:Dart 总是先去微任务队列中查询是否有可执行的任务,如果没有,才会处理后续的事件队列的流程。配合使用async、await的情况

void call() async {
  Logger("start");
  Future(() => "Future1").then((value) => Logger(value));
  scheduleMicrotask(() {
    Logger("microTask1");
    scheduleMicrotask(() {
      Logger("microTask2");
    });
  });
  var v = await Future(() => "Future2");
  Logger(v);
  scheduleMicrotask(() {
    Logger("microTask3");
  });
  Logger("end");
}

运行结果

flutter: 2023-03-20 17:23:04.703378 - start
flutter: 2023-03-20 17:23:04.783701 - microTask1
flutter: 2023-03-20 17:23:04.784461 - microTask2
flutter: 2023-03-20 17:23:04.791345 - Future1
flutter: 2023-03-20 17:23:04.792122 - Future2
flutter: 2023-03-20 17:23:04.792347 - end
flutter: 2023-03-20 17:23:04.792815 - microTask3

后续结果会在await后执行;

相关文章
|
4月前
|
存储 前端开发 JavaScript
事件循环机制是什么
【8月更文挑战第3天】事件循环机制是什么
38 1
|
5月前
|
前端开发 编译器 程序员
协程问题之为什么 C++20 的协程代码比其他语言的协程 demo 长很多如何解决
协程问题之为什么 C++20 的协程代码比其他语言的协程 demo 长很多如何解决
|
7月前
|
编解码 Dart UED
Flutter单线程异步及Isolate使用过程遇到的问题
Flutter单线程异步及Isolate使用过程遇到的问题 在Flutter中,所有的代码都运行在单线程中。这意味着如果我们的代码执行时间过长,就会导致UI线程卡顿,影响用户体验。因此,Flutter提供了一些异步机制来解决这个问题。
164 0
|
Dart JavaScript 前端开发
带你读《深入浅出Dart》十六、事件循环和协程机制(1)
带你读《深入浅出Dart》十六、事件循环和协程机制(1)
119 0
带你读《深入浅出Dart》十六、事件循环和协程机制(4)
带你读《深入浅出Dart》十六、事件循环和协程机制(4)
带你读《深入浅出Dart》十六、事件循环和协程机制(5)
带你读《深入浅出Dart》十六、事件循环和协程机制(5)
带你读《深入浅出Dart》十六、事件循环和协程机制(3)
带你读《深入浅出Dart》十六、事件循环和协程机制(3)
带你读《深入浅出Dart》十六、事件循环和协程机制(2)
带你读《深入浅出Dart》十六、事件循环和协程机制(2)
|
Dart JavaScript 前端开发
《深入浅出Dart》事件循环和协程机制
事件循环和协程机制 Dart实现异步的方式同Javascript类似,如果你掌握Javascript的事件循环机制,那么学习Dart的异步机制就非常简单了 在 Dart 中,事件循环和协程是实现异步编程的核心机制。它们使得我们能够以非阻塞的方式处理异步操作,并允许在异步操作期间暂停和继续执行代码。本文将深入探讨 Dart 的事件循环和协程机制,并结合代码示例进行详细说明。
232 0
|
Dart 算法 网络协议
dart线程学习讲解
Dart是一种基于对象的编程语言,其线程底层原理主要涉及两个方面:内存管理和并发执行。
dart线程学习讲解