Дротик изолирует как рабочие
Отредактировано, чтобы сделать вопрос более понятным.
Я пытаюсь работать с изолятами (или веб-работниками) в 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");
});
}