run<R> 静态方法

  1. @Since("2.19")
Future<R> run<R>(
  1. FutureOr<R> computation(
      ),
    1. {String? debugName}
    )

    在新的隔离器中运行 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;
    }