6

编辑以使问题更清楚。

我正在尝试在 Dart 中使用 Isolates(或 Web Workers)。我能找到的在主线程和隔离线程之间进行通信的唯一方法是发送调用,然后从主线程。但这是主线程将一些数据传递给隔离的好方法。

如果我希望隔离者成为生成信息的人怎么办?就像一个游戏引擎,它在一个工作线程中完成所有物理,然后将更新的世界信息发送到主线程?在 JavaScript 中,您可以随时发送数据。Dart 中是否有有效的方法?还是我还要等主线程给我打电话,然后再传给它?

PS我想知道,是否调用&然后阻塞线程直到回复完成?

4

4 回答 4

5

从 Dart 1.0 开始,您可以像这样使用隔离:

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

void doStuff(SendPort sendPort) {
  print('hi from inside isolate');
  ReceivePort receivePort = new ReceivePort();
  sendPort.send(receivePort.sendPort);

  receivePort.listen((msg) {
    print('Received in isolate: [$msg]');
    sendPort.send('ECHO: $msg');
  });

}

void main() {
  SendPort sendPort;

  ReceivePort receive = new ReceivePort();
  receive.listen((msg) {
    if (sendPort == null) {
      sendPort = msg;
    } else {
      print('From isolate: $msg');
    }
  });

  int counter = 0;

  Isolate.spawn(doStuff, receive.sendPort).then((isolate) {
    new Timer.periodic(const Duration(seconds:1), (t) {
      sendPort.send('Count is ${counter++}');
    });
  });
}
于 2014-01-20T03:57:43.353 回答
3

警告:此代码仅适用于非常旧版本的 Dart。它不适用于 Dart 1.0 或更高版本。

正如您提到将消息发布到隔离区,您需要处理它的发送端口。

#import('dart:isolate');

main() {
  SendPort sendPort = spawnFunction(doWork);
  sendPort.call("hey 1").then((String res) => print("result was: [$res]"));
  sendPort.call("hey 2").then((String res) => print("result was: [$res]"));
}

doWork() {
  port.receive((msg, reply) {
    msg = "msg $msg";
    reply.send(msg);
  });
}

然而,由于 Dart 主线程本身就是一个隔离,你可以使用全局端口函数向它发送数据:

#import('dart:isolate');
#import('dart:io');

main() {
   port.receive((data, reply) {
       // in here you can access objects created in the main thread
       print("handle [${data['text']}] for index ${data['index']}");
   });

   SendPort workPort = spawnFunction(doWork);
   workPort.send("msg", port.toSendPort());
}

doWork() {
   port.receive((msg, reply) {
      int i = 0;
      new Timer.repeating(1000, (Timer timer) {
         i++;
         var data = {
            "text": "$msg $i",
            "index": i
         };
         print("sending $data");
         reply.send(data);
      });
   });
}

请注意,对于可以在隔离之间来回发送的内容存在某些限制,并且当前隔离在 JS 和 VM 上的行为不同。当前的限制在这里得到了很好的描述。

于 2012-04-24T21:22:51.623 回答
1

这是一个示例,其中父进程创建了两个隔离,然后两个隔离也与父进程一起相互通信。

家长代码:

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

main() {
  querySelector('#output').text = 'Your Dart app is running.';
  int counter = 0;

  // Parent - Child 1
  SendPort csendPort1;
  ReceivePort receivePort1 = new ReceivePort();
  // Parent - Child 2
  SendPort csendPort2;
  ReceivePort receivePort2 = new ReceivePort();
  // Child1 - Child2
  SendPort csendPort11;
  SendPort csendPort12;

  // Child 1
  receivePort1.listen((msg) {
    if (csendPort1 == null) {
      csendPort1 = msg;
    } else if (csendPort11 == null) {
      csendPort11 = msg;
    } else {
      print('$msg');`enter code here`
    }
  });

  bool child1 = false;
  Isolate.spawnUri(Uri.parse('child.dart'), [], receivePort1.sendPort).then((isolate) {
    print('Child 1 isolate spawned');
    new Timer.periodic(const Duration(milliseconds: 500), (t) {
      if (csendPort11 != null && csendPort12 != null && child1 == false) {
        child1 = true;
        csendPort12.send(csendPort11);
      } else {
        csendPort1.send('Parent-Child1: ${counter++}');
      }
    });
  });

  // Child 2
  receivePort2.listen((msg) {
    if (csendPort2 == null) {
      csendPort2 = msg;
    } else if (csendPort12 == null) {
      csendPort12 = msg;
    } else {
      print('$msg');
    }
  });

  bool child2 = false;
  Isolate.spawnUri(Uri.parse('child.dart'), [], receivePort2.sendPort).then((isolate) {
    print('Child 2 isolate spawned');
    new Timer.periodic(const Duration(milliseconds: 500), (t) {
      if (csendPort11 != null && csendPort12 != null && child2 == false) {
        child2 = true;
        csendPort11.send(csendPort12);
      } else {
        csendPort2.send('Parent-Child2: ${counter++}');
      }
    });
  });
}

子代码:

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

int pcounter = 0;
int ccounter = 0;

SendPort csendPort;
void handleTimeout() {
  csendPort.send("${ccounter++}");
}

main(List<String> args, SendPort psendPort) {
  // Parent Comm
  ReceivePort creceivePort1 = new ReceivePort();
  psendPort.send(creceivePort1.sendPort);

  creceivePort1.listen((msg) {
    psendPort.send('Child-Parent: ${pcounter++} - ${msg}');
  });

  // Child-Child Comm
  ReceivePort creceivePort2 = new ReceivePort();
  psendPort.send(creceivePort2.sendPort);

  creceivePort2.listen((msg) {
    if (csendPort == null) {
      csendPort = msg;
      csendPort.send("${ccounter++}");
    } else {
      print("Child-Child: $msg");
      var duration = const Duration(milliseconds: 2000);
      new Timer(duration, handleTimeout);
    }
  });
}

HTML 代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="scaffolded-by" content="https://github.com/google/stagehand">
    <title>WebIsolateTest</title>
    <link rel="stylesheet" href="styles.css">
    <script defer src="main.dart" type="application/dart"></script>
    <script defer src="packages/browser/dart.js"></script>
</head>

<body>

  <div id="output"></div>

</body>
</html>
于 2016-03-07T18:32:47.387 回答
0

您现在可以使用MessageBox类以相反的方式进行通信。此代码在收到 MessageBox 的 Sink 端后立即从 Isolate 代码发送一条消息。主线程接收 Isolate 发送的消息,并在 Dartium 的控制台上打印出来。收到接收器后,您可以启动游戏逻辑并使用接收到的接收器对象发送更新。

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

void main() {
  IsolateSink isolateSink = streamSpawnFunction(myIsolateEntryPoint);
  MessageBox isolateMessageBox = new MessageBox();
  isolateSink.add(isolateMessageBox.sink);
  isolateMessageBox.stream.listen((String data) {
    print(data);
  });
}

void myIsolateEntryPoint() {
  stream.listen((IsolateSink messageBoxSink) {
    messageBoxSink.add("Test");
  });
}
于 2013-07-22T10:24:49.180 回答