Dart 2.15更新后isolate应该这么用

序言

2021年的最后一天, Dart 官方发布了 dart 2.15 版本,该版本优化了很多内容,今天我们要重点说说 isolate 工作器。官方推文链接

在探索新变化之前,我们来回忆巩固一下 isolate 的使用。

isolate 的作用

问题:Flutter 基于单线程模式使用协程进行开发,为什么还需要 isolate

首先我们要明确 并行(isolate并发(future)的区别。下面我们通过简单的例子来进行说明 。Demo 是一个简单的页面,中间放置一个不断转圈的 progress 和一个按键,按键用来触发耗时方法。

  • 方式一: 我们将耗时操作使用 future 的方式进行封装

结论:使用 future 的方式来消费耗时操作,由于仍然是单线程在进行工作,异步只是在同一个线程的并发操作,仍会阻塞UI的刷新。

  • 方式二: 使用 isolate 创建新线程,避开主线程,不干扰UI刷新

结论:使用 isolate 实现了多线程并行,在新线程中进行耗时操作不会干扰UI线程的刷新。

isolate 的局限性,为什么需要优化?

iso 有两点较为重要的局限性。

  • isolate 消耗较重,除了创建耗时,每次创建还至少需要2Mb的空间,有OOM的风险。
  • isolate 之间的内存空间各自独立,当参数或结果跨 iso 相互传递时需要深度拷贝,拷贝耗时,可能造成UI卡顿。

isolate 新特性

Dart 2.15 更新, 给 iso 添加了组的概念,isolate 工作特征可简单总结为以下两点:

  • Isolate 组中的 isolate 共享各种内部数据结构
  • Isolate 组仍然阻止isolate 间共享访问可变对象,但由于 isolate 组使用共享堆实现,这也让其拥有了更多的功能。

官方推文中举了一个例子

工作器 isolate 通过网络调用获得数据,将该数据解析为大型 JSON 对象图,然后将这个 JSON 图返回到主 isolate 中。

Dart 2.15 之前:执行该操作需要深度复制,如果复制花费的时间超过帧预算时间,就会导致界面卡顿。

使用 Dart 2.15 :工作器 isolate 可以调用 Isolate.exit(),将其结果作为参数传递。然后,Dart 运行时将包含结果的内存数据从工作器 isolate 传递到主 isolate 中,无需复制,且主 isolate 可以在固定时间内接收结果。

重点:提供 Isolate.exit() 方法,将包含结果的内存数据从工作器 isolate 传递到主 isolate,过程无需复制。

附注: 使用 Dart 新特性,需将 flutter sdk 升级到 2.8.0 以上 链接

isolate中:exit 和 send 的区别及用法

Dart 更新后,我们将数据从 工作器 isolate(子线程)回传到 主 isolate(主线程)有两种方式。

  • 方式一: 使用 send

点击进入 send 方法查看源码注释,看到这样一句话:

结论:send 本身不会阻塞,会立即发送,但可能需要线性时间成本用于复制数据。

  • 方式二:使用 exit

官网 给出的解释如下:

结论:隔离之间的消息传递通常涉及数据复制,因此可能会很慢,并且会随着消息大小的增加而增加。但是 exit(),则是在退出隔离中保存消息的内存,不会被复制,而是被传输到主 isolate。这种传输很快,并且在恒定的时间内完成。

我们把上面 demo 中的 _entryPoint 方法做一下优化,修改如下:

总结:使用 exit() 替代 SendPort.send,可规避数据复制,节省耗时。

isolate

如何创建一个 isolate 组?官方给出的解释如下:

When an isolate calls Isolate.spawn(), the two isolates have the same executable code and are in the same isolate group. Isolate groups enable performance optimizations such as sharing code; a new isolate immediately runs the code owned by the isolate group. Also, Isolate.exit() works only when the isolates are in the same isolate group.

当在 isolate 中调用另一个 isolate 时,这两个 isolate 具有相同的可执行代码,并且位于同一隔离组。

PS: 小轰暂时也没有想到具体的使用场景,先暂放一边吧。

实践:isolate 如何处理连续数据

结合上面的耗时方法calculateEvenCountisolate 处理连续数据需要结合 stream 流的设计。具体 demo 如下:

参考链接


Dart 2.15 更新后 isolate 应该这么用

发布者

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注