Дротик изолирует как рабочие

Отредактировано, чтобы сделать вопрос более понятным.

Я пытаюсь работать с изолятами (или веб-работниками) в Dart. Единственные способы связи между основным и изолированным потоками, которые я могу найти, - это отправка и вызов, а затем - из основного потока. Но это хороший способ для основного потока передать некоторые данные в изолятор.

Что если я хочу, чтобы изолят был тем, кто генерирует информацию? Как игровой движок, который выполняет всю физику в работнике, а затем отправляет обновленную информацию о мире в основной поток? В JavaScript вы можете отправлять данные в любое время. Есть ли эффективный способ в дартс? Или мне все еще нужно дождаться, пока главный поток позвонит мне, а затем передать его ему?

PS Интересно, звонит и затем блокирует поток, пока ответ не будет сделан или нет?

4 ответа

Решение

ВНИМАНИЕ: этот код работает только на очень старых версиях Dart. Это не работает на Dart 1.0 или более поздней версии.

Поскольку вы упоминаете, чтобы публиковать сообщения в изолятор, вам нужно иметь указатель на его sendport.

#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 и на виртуальной машине. Текущие ограничения хорошо описаны здесь.

Начиная с 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++}');
    });
  });
}

Вот пример, где родитель создает два изолята, а затем два изолята также общаются друг с другом вместе с родительским процессом.

Родительский код:

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>

Теперь вы можете использовать класс MessageBox для общения с другими людьми. Этот код отправляет сообщение из кода Isolate, как только он получает конец Sink для MessageBox. Главный поток получает сообщения, отправленные с 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");
  });
}
Другие вопросы по тегам