2012-04-24 42 views
6

Editado para hacer la pregunta más clara.Dart Isolates As Workers

Estoy tratando de trabajar con aislamientos (o Web Workers) en Dart. Las únicas formas en que puedo encontrar para comunicarme entre los hilos principal y aislado son enviar y llamar y luego desde el hilo principal. Pero esa es una buena forma para que el hilo principal pase algunos datos al aislado.

¿Qué pasa si quiero que el aislado sea el que genera la información? ¿Como un motor de juego que hace toda la física en un trabajador y luego envía una información mundial actualizada al hilo principal? En JavaScript puede enviar datos en cualquier momento. ¿Hay una manera eficiente en Dart? ¿O todavía tengo que esperar que el hilo principal me llame y luego se lo pase?

P.S. Me pregunto, ¿llama al & y luego bloquea el hilo hasta que la respuesta finalice o no?

Respuesta

3

ADVERTENCIA: este código solo funciona en versiones muy antiguas de Dart. No funciona en Dart 1.0 o posterior.

Como mencionas para publicar mensajes en un aislado, necesitas tener un control en su 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); 
    }); 
} 

sin embargo, desde el hilo principal Dart es en sí un aislado puede enviar datos a la misma a través del puerto mundial función:

#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); 
     }); 
    }); 
} 

Nota hay ciertos límites sobre lo que se puede enviar de vuelta y sucesivamente entre aislamientos y también actualmente los aislamientos actúan de manera diferente en JS y en la máquina virtual. Las limitaciones actuales están bien descritas here.

+0

pero lo que es si quiero que mi aislamiento para generar/actualizar? Como un motor de juego. Se supone que ejecuta todos los cálculos y luego pasa los estados actualizados del objeto en el juego. ¿Existe un mecanismo eficiente para eso o tengo que construirlo sobre aislamientos? – Pijusn

+0

@Pius no puede enviar referencias a un aislante, todos los datos trabajados se copian como se describe aquí http://api.dartlang.org/dart_isolate/SendPort.html#send –

+0

No estoy hablando de referencias en absoluto. Estoy hablando de datos. ¿Alguna vez trabajó con Web Workers en JavaScript? Puede enviar datos del trabajador en cualquier momento. Y tanto, como quieras. El trabajador podría trabajar y enviar datos sin siquiera escuchar el hilo principal, mientras que el hilo principal podría simplemente recibir datos utilizando una función de devolución de llamada. Estoy hablando de self.postMessage función equivalente en aislar. – Pijusn

0

Ahora puede usar la clase MessageBox para comunicarse al revés. Este código envía un mensaje desde el código Aislar tan pronto como recibe el extremo del Sumidero del MessageBox. El hilo principal recibe los mensajes enviados desde el Aislante y los imprime en la consola de Dartium. Una vez que reciba el Sink, puede iniciar su lógica de juego y enviar actualizaciones utilizando el objeto receptor recibido.

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"); 
    }); 
} 
3

A partir del dardo 1.0, puede utilizar los aislados de esta manera:

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++}'); 
    }); 
    }); 
} 
1

He aquí un ejemplo en el que los padres crea dos aislamientos y luego dos aislados también se comuniquen entre sí, junto con el proceso padre.

Código de Padres: Código

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++}'); 
     } 
    }); 
    }); 
} 

Niño: Código

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: los datos

<!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> 
+0

El código anterior funciona con la versión 1.14.2 dardo SDK y en Chrome, Firefox y EI11 – user2569304