Есть ли какой-нибудь пример для dart `spawnUri(...)` в библиотеке "dart:isolate"?
E сть spawnUri(uri)
функция в dart:isolate
, но я не нахожу никакого примера. Я угадал его использование, но не удалось.
Предположим, что есть 2 файла, в первом он будет вызывать spawnUri
для 2-го и общаться с ним.
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 ответа
ВНИМАНИЕ: этот код устарел.
Замените свой 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])));
}
Вот простой пример, который работает с 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');
});
}
Строительство состоит из двух этапов:
pub build
dart2js -m web/worker.dart -obuild/worker.dart.js
Смотрите полный проект здесь: https://github.com/sethladd/dart_worker_isolates_dart2js_test
Этот гист: https://gist.github.com/damondouglas/8620350 предоставляет работающий (я проверял это) пример Dart 1.5. Isolate.spawn(...)
пример можно найти и там.
Воспроизведение здесь (добавление операторов импорта):
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"); });
}
Бесстыдно скопировано с Dart Web Development ›Пример использования Isolate.spawn Надеюсь, автор не против
Появившийся изолят понятия не имеет, где и как реагировать на своего родителя.
В родительском объекте вы можете создать ReceivePort, который будет получать все сообщения от дочерних изолятов. Всякий раз, когда вы создаете изолят, передайте ему экземпляр SendPort из вашего ReceivePort (через аргумент сообщения 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 из каждого изолята и в конечном итоге регистрировать их как сервисы.