Skip to content

Isolate

Flutter 的多线程和其他语言几乎不一样。 很早前 Dart 被用于 Web,现在还被编译为 JS,所以在 Web 平台上,Isolate 的功能存在一些限制。 这是因为 Dart 被转换为 JS,而 JS 是单线程的。Dart Web 中,由于 Web Worker 的安全策略限制,无法直接创建和操作 Isolate。Isolate 在 Web 平台上的替代方案是使用 spawnUri() 方法创建 Worker,并通过 postMessage() 方法进行通信。

Isolate 误区

尽管 Isolate 在很多方面类似于线程,但它实际上是一种并发执行的独立执行上下文。每个 Isolate 都有自己的内存空间和事件循环,并且相互之间不能直接共享数据。因此,Isolate 更类似于运行在单独进程中的独立执行单元,而不是线程。不要将 Isolate 视为用于线程同步和共享数据的机制。
Isolate 无法直接通信 Isolate 之间默认情况下是无法直接通信的,它们是完全隔离的,无法共享变量或直接传递消息。要在 Isolate 之间进行通信,需要使用 SendPort 和 ReceivePort 来发送和接收消息。SendPort 可以将消息发送到目标 Isolate 的 ReceivePort,然后目标 Isolate 可以通过其 ReceivePort 接收和处理该消息。
Isolate 不能随意销毁和重启 一旦 Isolate 被创建,它会持续运行直到完成或被显式终止。Isolate 实例无法被随意销毁或重启。要终止一个 Isolate,可以调用 kill 方法或向其发送一个特殊指令告知其终止。然而,这并不是一个优雅的终止方式,并且可能会导致资源泄漏和不可预测的行为。最佳实践是让 Isolate 自然地完成其工作并退出。如果需要长时间运行的任务,可以将其拆分为可中断的子任务,并使用消息传递和状态管理来实现灵活的控制。
Isolate 的成本高昂 创建和启动新的 Isolate 是一个开销较大的操作,因为每个 Isolate 都需要自己的内存空间和事件循环。因此,频繁地创建和销毁 Isolate 可能会对性能产生负面影响。在需要并发执行的情况下,优先考虑使用线程或其他并发机制来减少 Isolate 的使用
看完这些,我相信你成魔了,这哪里是多线程?这就是 Dart 的非主流之处,既然不能共享内存,那么多线程存在还有什么意义?其实这反而变得更加安全。

如何使用 Isolate

绝大多数情况下,你并不会接触到 Isolate,因为 Future 足以帮你解决很多问题。但 Isolate 的使用,复杂,在后续我们会补充更加详细的使用方法。本篇文章中,我们将介绍在 Flutter 中最长使用 Isolate 的场景,和如何最简单的方式去使用。
在 Flutter 中,可以使用 compute() 函数来创建内置的 Isolate。compute() 函数提供了一种简单的方式,用来在后台执行耗时的计算任务,并自动管理 Isolate 的创建和销毁过程。 compute() 函数的使用方式如下:

dart
Future<T> compute<in, out>(Function function, in message)

参数解释:

  • function:要在新的 Isolate 中执行的函数。
  • message:传递给函数的参数。

返回值为一个 Future,用于接收函数的返回值。

下面是一个示例,演示如何使用 compute() 函数在后台执行一个计算任务:

dart
import 'package:flutter/foundation.dart';

void main() async {
  var result = await compute(fibonacci, 20);
  print('Fibonacci: $result');
}

int fibonacci(int n) {
  if (n <= 0) return 0;
  if (n == 1) return 1;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

在上述示例中,compute() 函数用于执行 fibonacci 函数,并传递参数 20。该计算任务将在后台的 Isolate 中执行,不会阻塞主线程。当计算完成后,通过 await 关键字等待 compute() 函数的返回值,并将结果打印出来。

使用 compute() 函数可以简化后台计算任务的实现,避免手动管理 Isolate 的创建和销毁。但需要注意的是,compute() 中执行的函数必须是顶层函数或静态类成员函数,因为 compute() 需要通过序列化和反序列化来传递函数参数和返回值。

总而言之,compute() 函数是 Flutter 内置的一种方式,用于在后台执行计算任务,并自动处理 Isolate 的创建和销毁。它为开发者提供了更便捷的方式来处理耗时的计算任务,同时保持应用的响应性。

哪些场景可以使用 compute() 函数

compute的使用很广泛,对于较大内存占用的计算行为,都建议使用compute,比如图片字节集转字符串,接口请求时未知大小的字符串到JSON转换。以DIO为例,DIO的转换器(自动将Json转换为Map)都是使用compute)

dart
import 'dart:convert';
import 'package:flutter/foundation.dart';

/// The default [Transformer] for [Dio].
///
/// [BackgroundTransformer] will do the deserialization of JSON in
/// a background isolate if possible.
class RequestFormer extends SyncTransformer {
  RequestFormer() : super(jsonDecodeCallback: _parseJson);
}

/// Must be top-level function
parseAndDecode(String response) {
  return jsonDecode(response);
}

/// ISOLATED
_parseJson(String text) {
  return compute(parseAndDecode, text);
}

compute() 函数在 Flutter 中用于在后台执行计算任务,并自动管理 Isolate 的创建和销毁。Future执行较大的运算,极大可能造成UI阻塞,所以建议使用compute()

仅用于培训和测试,通过使用本站代码内容随之而来的风险与本站无关。版权所有,未经授权请勿转载,保留一切权利。
ICP备案号:滇ICP备15009214号-13   公安网备:滇公网安备 53312302000061号