在dart:isolate“中有dart的`spawnUri(...)`的例子吗?

时间:2013-06-25 14:06:31

标签: dart dart-isolates

spawnUri(uri)中有一个dart:isolate函数,但我没有找到任何示例。我已经猜到了它的用法,但失败了。

假设有2个文件,在第一个文件中,它将为第二个文件调用spawnUri,并与之通信。

first.dart

import "dart:isolate";

main() {
  ReceivePort port = new ReceivePort();
  port.receive((msg, _) {
    print(msg);
    port.close();
  });
   var c = spawnUri("./second.dart");
   c.send(["Freewind", "enjoy dart"], port.toSendPort());
}

second.dart

String hello(String who, String message) {
   return "Hello, $who, $message";
}

void isolateMain(ReceivePort port) {
  port.receive((msg, reply) => reply.send(hello(msg[0], msg[1]));
}

main() {}

但是这个例子不起作用。我不知道什么是正确的代码,如何修复它?

4 个答案:

答案 0 :(得分:6)

这是一个适用于Dart 1.0的简单示例。

app.dart:

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

main() {
  Element output = querySelector('output');

  SendPort sendPort;

  ReceivePort receivePort = new ReceivePort();
  receivePort.listen((msg) {
    if (sendPort == null) {
      sendPort = msg;
    } else {
      output.text += 'Received from isolate: $msg\n';
    }
  });

  String workerUri;

  // Yikes, this is a hack. But is there another way?
  if (identical(1, 1.0)) {
    // we're in dart2js!
    workerUri = 'worker.dart.js';
  } else {
    // we're in the VM!
    workerUri = 'worker.dart';
  }

  int counter = 0;

  Isolate.spawnUri(Uri.parse(workerUri), [], receivePort.sendPort).then((isolate) {
    print('isolate spawned');
    new Timer.periodic(const Duration(seconds: 1), (t) {
      sendPort.send('From app: ${counter++}');
    });
  });
}

worker.dart:

import 'dart:isolate';

main(List<String> args, SendPort sendPort) {
  ReceivePort receivePort = new ReceivePort();
  sendPort.send(receivePort.sendPort);

  receivePort.listen((msg) {
    sendPort.send('ECHO: $msg');
  });
}

建设分为两个步骤:

  1. pub build
  2. dart2js -m web/worker.dart -obuild/worker.dart.js
  3. 请在此处查看完整项目:https://github.com/sethladd/dart_worker_isolates_dart2js_test

答案 1 :(得分:2)

警告:此代码已过期。

second.dart 替换为以下内容以使其正常工作:

import "dart:isolate";

String hello(String who, String message) {
  return "Hello, $who, $message";
}

main() {
  port.receive((msg, reply) => reply.send(hello(msg[0], msg[1])));
}

答案 2 :(得分:1)

这个要点:https://gist.github.com/damondouglas/8620350提供了一个工作(我测试过)的Dart 1.5示例。此处也可以找到Isolate.spawn(...)示例。

在此处重现(添加import语句):

echo.dart:

import 'dart:isolate';
void main(List<String> args, SendPort replyTo) {
  replyTo.send(args[0]);
}

main.dart:

import 'dart:isolate';
import 'dart:async';
main() {
  var response = new ReceivePort();
  Future<Isolate> remote = Isolate.spawnUri(Uri.parse("echo.dart"), ["foo"], response.sendPort);
  remote.then((_) => response.first)
    .then((msg) { print("received: $msg"); });
}

答案 3 :(得分:1)

无耻复制 Dart Web Development › Example on how to use Isolate.spawn 我希望作者不介意

产生的分离物不知道在哪里/如何回应其父母。

在父级中,您可以创建一个ReceivePort,它将接收来自子隔离区的所有消息。 无论何时生成隔离,请将它从ReceivePort传递给SendPort实例(通过Isolate.spawn的消息参数)。

子隔离可能/应该创建自己的ReceivePort,因此它可以接收消息。 实例化时,子隔离区必须将其自己的SendPort(从其自己的ReceivePort)发送到其父级(通过父级的SendPort)。

当前的API本身并没有帮助。但它为全面实施提供了所有必要的构建模块。

您可能需要将消息包装在标题内,这些内容如下:

class _Request {
  /// The ID of the request so the response may be associated to the request's future completer.
  final Capability requestId;
  /// The SendPort we must respond to, because the message could come from any isolate.
  final SendPort   responsePort;
  /// The actual message of the request.
  final dynamic    message

  const _Request(this.requestId, this.responsePort, this.message);
}

class _Response {
  /// The ID of the request this response is meant to.
  final Capability requestId;
  /// Indicates if the request succeeded.
  final bool       success;
  /// If [success] is true, holds the response message.
  /// Otherwise, holds the error that occured.
  final dynamic    message;

  const _Response.ok(this.requestId, this.message): success = true;
  const _Response.error(this.requestId, this.message): success = false;
}

每个隔离区都可以有这样的单例消息总线:

final isolateBus = new IsolateBus();

class IsolateBus {
  final ReceivePort _receivePort = new ReceivePort();
  final Map<Capability, Completer> _completers = {};

  IsolateBus() {
    _receivePort.listen(_handleMessage, onError: _handleError);
  }

  void _handleMessage(portMessage) {
    if (portMessage is _Request) {
      // This is a request, we should process.
      // Here we send back the same message
      portMessage.responsePort.send(
        new _Response.ok(portMessage.requestId, portMessage.message));

    } else if (portMessage is _Response) {
      // We received a response
      final completer = _completers[portMessage.requestId];
      if (completer == null) {
        print("Invalid request ID received.");
      } else if (portMessage.success) {
        completer.complete(portMessage.message);
      } else {
        completer.completeError(portMessage.message);
      }

    } else {
      print("Invalid message received:  $portMessage");
    }
  }

  void _handleError(error) {
    print("A ReceivePort error occured:   $error");
  }

  Future request(SendPort port, message) {
    final completer = new Completer();
    final requestId = new Capability();
    _completers[requestId] = completer;

    port.send(new _Request(requestId, _receivePort.sendPort, message));

    return completer.future;
  }
}

SendPort anotherIsolatePort = ...
isolateBus.request(anotherIsolatePort, "Some message");

这只是一个架构示例。你当然可以推出自己的产品。 这可以扩展为支持通知(没有响应的请求),流等。

可能需要一个全局隔离注册表来跟踪每个隔离区中的所有SendPort实例,并最终将它们注册为服务。