Appearance
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()