Dart 之异步模型

前言

Dart异步模型?模型就算了还是异步的,太难了吧。但当你真的理解异步模型后,你会感叹异步模型的出现也太完美了吧。为啥说异步模型出现很完美呢?因为它通过事件循环+任务队列的方式,即满足了异步需求的同时又解决了Dart单线程的局限。那它都是怎么解决的呢?相信读完这篇内容你就明白了。

一、为啥需要异步模型?

Dart异步模型的出现是为了满足异步操作的需求和解决Dart单线程的局限。下面分别介绍一下都有哪些异步操作需求和单线程有哪些局限。

异步操作需求: 异步操作就是为了让耗时的操作(如网络请求)不会影响后面的操作。也就是说当有耗时操作时,程序不会等待耗时操作完成,而是继续执行接下来的操作。下面是一些常见的耗时操作:

  • 网络请求:如Http请求。
  • 文件操作:如读写文件、数据库操作。
  • 图像处理:如格式处理。

单线程的局限: 单线程就是按照顺序执行且一次只能做一件事,当遇到耗时操作时就会卡死。它的局限有以下几点:

  • 不能充分利用资源:单线程只使用一核CPU不能利用多核CPU(浪费了资源)。
  • 耗时任务会阻塞整个线程:单线程按顺序执行,遇到耗时的就会和它一起耗,直到耗时操作完成(浪费了时间)。

二、Dart异步模型

Dart异步模型由事件循环+任务队列实现,其将I/O操作交给操作系统执行,不会阻塞当前线程。那Dart咋知道操作系统执行完了呢?事件循环会负责监听操作系统返回的结果,并在主线程空闲的时候触发回调。下面将具体介绍一下异步模型的核心------事件循环(Event Loop)

2.1、学前必备

Dart是单线程语言,其所有任务都是通过主线程(主Isolate)负责执行。

Dart选择单线程,那它有哪些优势呢?

答:单线程按照顺序执行,天然避免了多线程的资源竞争和同步问题(如锁、死锁)

Dart是单线程如何实现的并发和并行呢?

答:通过事件循环机制 实现异步并发,通过开辟多个Isolate实现并行计算。(Isolate相关内容后续文章介绍)

2.2、事件循环

Dart异步模型通过事件循环调度和执行任务实现交错执行任务,从而实现并发。它的核心逻辑是维护两个任务队列,所以说Dart异步模型是由事件循环+任务队列实现的。下面先了解一下任务队列,然后再了解事件循环都是如何循环调度的。

任务队列: 按照任务执行优先级分为两类。

  • 微任务队列:可以理解为有多个微任务排队准备执行(微任务具有较高优先级)。
  • 事件任务队列:可以理解为有多个事件任务排队准备执行(事件任务优先级低于微任务)。

调度规则: 优先级高的先执行。

循环执行规则: 首先判断微任务队列是否为空,若微任务队列不为空则执行微任务队列中所有内容,执行完后判断事件任务队列是否为空,若不为空则执行事件任务队列中排在首位的事件任务,执行完后,返回判断微任务队列是否为空,若不为空则执行所有微任务队列中的任务,若为空则继续执行事件任务队列中的第二个事件任务(假设有第二个,没有则结束事件循环)。

代码示例:

Dart 复制代码
void eventLoop() {
    while (true) {
        if (微任务队列不为空) {
            执行微任务队列中所有微任务;
        } else if (事件队列不为空) {
            处理事件任务队列中的第一个事件任务;
        } else {
            等待新的事件;
        }
    }
}

三、需要注意

  • Dart虽然是单线程,但大可不必担心性能问题,据有测试数据在Dart VM 可每秒处理20多万个微任务事件,事件任务处理也可满足常规需求。
  • 微任务并不是比事件任务快,只是优先级高,先执行(通常微任务都是比较小的任务,不建议执行耗时操作会导致事件任务饥饿)。
  • 若同步代码中存在耗时操作(如I/O密集型操作),则会阻塞事件循环。因为同步代码优先执行,可采取将耗时操作进行拆分为多个微任务或使用Isolate并行计算。
  • 虽然单线程不能利用多核CPU,但可通过开辟多个Isolate利用多核实现并行计算。

下图为实际问题时可供选择的解决方案。

四、总结

本小节首先从Dart中为什么需要异步模型开始介绍了单线程的局限性和异步操作的需求,其次介绍了Dart单线程如何利用事件循环+任务队列实现异步模型,最后介绍了Dart异步模型中可能需要注意的点以及如何处理同步代码中的耗时操作。

事件循环 任务队列 需要注意的点
调度规则:优先级高的先执行 微任务队列 不用担心性能问题 微任务并不是比事件任务快 微任务通常为小任务,防止事件任务饥饿
循环执行规则: 首先执行完微任务队列中全部微任务, 然后执行事件任务中第一个事件任务, 结束后返回判断任务队列是否为空, 如此循环直到任务队列没有任务,等待任务。 事件任务队列 如何处理同步任务中的耗时操作? 判断任务是否可拆分为多个微任务, 若能则使用微任务调度, 若不能则选择开辟多个Isolate并行计算解决。
相关推荐
海水冷却3 小时前
Android 群组聊天怎么实现:基于 ZIM 的完整落地指南(附可运行 Demo)
android
三少爷的鞋6 小时前
现代 Android 架构指南:不要再主动设计 Callback 接口
android
TimeFine12 小时前
AI 编码工作流的设计
android·ai编程
2601_9498477512 小时前
Form-data 跨端三方库仓颉适配全流程
前端·javascript·flutter
骑着蜗牛撵大象32712 小时前
C++20 协程 × 屏障:手写一个 co_await 版 Barrier,让等待不再钉死线程
android·c++20·协程·并发编程·co_await·屏障同步
山东孙燕姿14 小时前
设备台账重构:从一张表到三层模型
android·java·网络·低代码·重构·rxjava
蒸鱼Yuzheng15 小时前
移动端 CPU 调度分析:线程亲和性、大小核迁移与卡顿
android·perfetto·性能分析·线程优化·cpu调度
booboosui15 小时前
安卓唤醒词:12 维 MFCC 加 DTW,阈值 1.8
android
大龄秃头程序员15 小时前
Flutter 中我为什么把 GetX 定位为高效率方案,而不是默认架构方案
flutter
传奇开心果15 小时前
Compose Multiplatform 共享边界实战:架构契约、互操作同步与可回退设计
android·kotlin