【问题标题】:Type conversion error when trying to use Isolate.spawn()尝试使用 Isolate.spawn() 时出现类型转换错误
【发布时间】:2021-11-22 06:25:04
【问题描述】:

我在使用 Isolate.spawn() 时遇到了 Dart 的泛型类型的问题。我觉得这应该可行,但它没有。

我正在尝试围绕 Isolate.spawn() 编写一个类型安全(-ish)的包装器,以确保我将有效类型传递给我想在另一个线程中运行的函数(输入参数),以及我从此函数获得的结果值的类型(输出结果值)。

所以,我创建了InputTypeOutputType 虚拟类作为我的输入和输出类型。 thread 函数是我想在另一个线程中运行的函数。 run 函数是实际的包装器:它应该接受在另一个线程中运行的函数,它是参数。

import 'dart:async';
import 'dart:isolate';

typedef Callback<I, R> = Future<R> Function(I input);

class Config<I, R> {
  final Callback<I, R> callback;
  final I arg;
  final SendPort port;
  Config(this.callback, this.arg, this.port);
}

class InputType {
  int arg;
  InputType(this.arg);
}

class OutputType {
  String str;
  OutputType(this.str);
}

Future<R> _spawn<I, R>(Config<I, R> conf) async {
  print("callback: ${conf.callback}");
  return await conf.callback(conf.arg);
}

void run<I, R>(Callback<I, R> func, I arg) async {
  ReceivePort resultPort = ReceivePort();

  Config<I, R> conf = Config<I, R>(func, arg, resultPort.sendPort);
  Isolate thread = await Isolate.spawn<Config<I, R>>(_spawn, conf);
  // ...
}

Future<OutputType> thread(InputType input) async {
  print("running in isolate");
  return OutputType("Hello, arg was: ${input.arg}");
}

void main() async {
  print("runtime");
  run<InputType, OutputType>(thread, InputType(123));
}

我遇到的结果错误:

$ dart isolate.dart                                                                                  
runtime
Unhandled exception:
type '(InputType) => Future<OutputType>' is not a subtype of type '(dynamic) => Future<dynamic>'
#0      _spawn (file:///home/antek/dev/dart/tests/generic/isolate.dart:24:27)
#1      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:286:17)
#2      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
^C

错误实际上来自这一行:

print("callback: ${conf.callback}");

有人知道如何解决这个问题吗?

【问题讨论】:

    标签: dart dart-isolates


    【解决方案1】:

    Dart hackity-hack 来救援。

    似乎将_spawn函数的引用传递给Isolate.spawn()时,类型信息正在丢失。

    我发现的一个解决方法是在调用回调的Config&lt;I, R&gt; 类中添加一个辅助函数。 Config&lt;I, R&gt; 的实例似乎包含有关类型的所有必要信息。因此,在我像这样修改了上面的示例之后:

    class Config<I, R> {
      final Callback<I, R> callback;
      final I arg;
      final SendPort port;
      Config(this.callback, this.arg, this.port);
    
      Future<R> call() async {
        return await callback(arg);
      }
    }
    
    // ...
    
    Future<R> _spawn<I, R>(Config<I, R> conf) async {
      var result = await conf.call();
      return result;
    }
    

    它开始正常工作。

    具有必要阻塞和单向通信的完整示例源:

    import 'dart:async';
    import 'dart:isolate';
    
    typedef Callback<I, R> = Future<R> Function(I input);
    
    class Config<I, R> {
      final Callback<I, R> callback;
      final I arg;
      final SendPort port;
      Config(this.callback, this.arg, this.port);
    
      Future<R> call() async {
        return await callback(arg);
      }
    }
    
    class InputType {
      int arg;
      InputType(this.arg);
    }
    
    class OutputType {
      String str;
      OutputType(this.str);
    }
    
    Future<R> _spawn<I, R>(Config<I, R> conf) async {
      var result = await conf.call();
      conf.port.send(result);
      return result;
    }
    
    Future<R> run<I, R>(Callback<I, R> func, I arg) async {
      ReceivePort resultPort = ReceivePort();
    
      Config<I, R> conf = Config<I, R>(func, arg, resultPort.sendPort);
      Future<Isolate> thread = Isolate.spawn<Config<I, R>>(_spawn, conf);
    
      var c = Completer<R>();
      resultPort.listen((data) {
        c.complete(data as R);
      });
    
      await c.future;
    
      resultPort.close();
      (await thread).kill();
      return c.future;
    }
    
    Future<OutputType> thread(InputType input) async {
      return OutputType("Hello, arg was: ${input.arg}");
    }
    
    void main() async {
      var result = await run<InputType, OutputType>(thread, InputType(123));
      print("main() result: ${result.str}");
    }
    

    【讨论】:

    • 就是这样!当你这样做时,_spawn 函数甚至不需要它的类型参数。它适用于任何Config。或者它的返回类型。没有使用返回值。
    猜你喜欢
    • 2012-09-03
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多