run<R> 静态方法
- @Since("2.19")
在新的隔离器中运行 computation
并返回结果。
int slowFib(int n) =>
n <= 1 ? 1 : slowFib(n - 1) + slowFib(n - 2);
// Compute without blocking current isolate.
var fib40 = await Isolate.run(() => slowFib(40));
如果 computation
是异步的(返回 Future<R>
),则在新的隔离器中等待此类 future 完成,然后在返回结果之前完成整个异步运算。
int slowFib(int n) =>
n <= 1 ? 1 : slowFib(n - 1) + slowFib(n - 2);
Stream<int> fibStream() async* {
for (var i = 0;; i++) yield slowFib(i);
}
// Returns `Future<int>`.
var fib40 = await Isolate.run(() => fibStream().elementAt(40));
如果 computation
抛出异常,隔离器将终止,并且该函数将抛出相同的错误。
Future<int> eventualError() async {
await Future.delayed(const Duration(seconds: 1));
throw StateError("In a bad state!");
}
try {
await Isolate.run(eventualError);
} on StateError catch (e, s) {
print(e.message); // In a bad state!
print(LineSplitter.split("$s").first); // Contains "eventualError"
}
任何未捕获的异步错误将也会终止计算,但会报告为 RemoteError,因为 addErrorListener 不提供原始错误对象。
结果是通过 exit 发送的,这意味着它直接发送到这个隔离器而无需复制。
计算函数及其结果(或错误)必须在隔离器之间发送。无法发送的对象包括打开的文件和套接字(请参阅 SendPort.send 了解详细信息)。
如果 computation
是闭包,则由于 Dart 实现的限制,它可能将意外的状态发送到隔离器。这可能会导致性能问题、内存使用增加(有关详细信息,请参阅 http://dartbug.com/36983)或,如果状态包含无法在隔离器之间传递的对象,则可能导致运行时失败。
void serializeAndWrite(File f, Object o) async {
final openFile = await f.open(mode: FileMode.append);
Future writeNew() async {
// Will fail with:
// "Invalid argument(s): Illegal argument in isolate message"
// because `openFile` is captured.
final encoded = await Isolate.run(() => jsonEncode(o));
await openFile.writeString(encoded);
await openFile.flush();
await openFile.close();
}
if (await openFile.position() == 0) {
await writeNew();
}
}
在这种情况下,您可以创建一个新的函数来调用 Isolate.run,该函数以参数形式接受所有必需的状态。
void serializeAndWrite(File f, Object o) async {
final openFile = await f.open(mode: FileMode.append);
Future writeNew() async {
Future<String> encode(o) => Isolate.run(() => jsonEncode(o));
final encoded = await encode(o);
await openFile.writeString(encoded);
await openFile.flush();
await openFile.close();
}
if (await openFile.position() == 0) {
await writeNew();
}
}
debugName
仅用于为新隔离器命名以用于调试。
实现
@Since("2.19")
static Future<R> run<R>(FutureOr<R> computation(), {String? debugName}) {
var result = Completer<R>();
var resultPort = RawReceivePort();
resultPort.handler = (response) {
resultPort.close();
if (response == null) {
// onExit handler message, isolate terminated without sending result.
result.completeError(
RemoteError("Computation ended without result", ""),
StackTrace.empty);
return;
}
var list = response as List<Object?>;
if (list.length == 2) {
var remoteError = list[0];
var remoteStack = list[1];
if (remoteStack is StackTrace) {
// Typed error.
result.completeError(remoteError!, remoteStack);
} else {
// onError handler message, uncaught async error.
// Both values are strings, so calling `toString` is efficient.
var error =
RemoteError(remoteError.toString(), remoteStack.toString());
result.completeError(error, error.stackTrace);
}
} else {
assert(list.length == 1);
result.complete(list[0] as R);
}
};
try {
Isolate.spawn(_RemoteRunner._remoteExecute,
_RemoteRunner<R>(computation, resultPort.sendPort),
onError: resultPort.sendPort,
onExit: resultPort.sendPort,
errorsAreFatal: true,
debugName: debugName)
.then<void>((_) {}, onError: (error, stack) {
// Sending the computation failed asynchronously.
// Do not expect a response, report the error asynchronously.
resultPort.close();
result.completeError(error, stack);
});
} on Object {
// Sending the computation failed synchronously.
// This is not expected to happen, but if it does,
// the synchronous error is respected and rethrown synchronously.
resultPort.close();
rethrow;
}
return result.future;
}