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

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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,858评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,372评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,282评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,842评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,857评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,679评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,406评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,311评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,767评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,945评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,090评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,785评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,420评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,988评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,101评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,298评论 3 372
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,033评论 2 355

推荐阅读更多精彩内容