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 发送的,这意味着它被发送到这个隔离器而没有复制。
computation
函数及其结果(或错误)必须在隔离器之间发送。无法发送的对象包括打开的文件和套接字(有关详细信息,请参阅 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;
}