2012-04-24 15 views
6

Modificato per rendere la domanda più chiara.Il dardo si isola come lavoratore

Sto provando a lavorare con Isolates (o Web Workers) in Dart. Gli unici modi che riesco a trovare per comunicare tra thread principali e isolati sono inviare e chiamare & quindi dal thread principale. Ma questo è un buon modo per il thread principale di passare alcuni dati all'isolato.

Che cosa succede se voglio che l'isolato sia quello che genera informazioni? Come un motore di gioco che fa tutta la fisica in un lavoratore e poi invia informazioni mondiali aggiornate al thread principale? In JavaScript è possibile inviare dati in qualsiasi momento. C'è un modo efficiente in Dart? O devo ancora aspettare il thread principale per chiamarmi e poi passarci sopra?

P.S. Mi chiedo, chiama & poi bloccare il thread fino a quando la risposta è stata fatta o no?

risposta

3

ATTENZIONE: questo codice funziona solo su versioni molto vecchie di Dart. Non funziona su Dart 1.0 o versioni successive.

Come si menziona per inviare messaggi a un isolato è necessario avere un handle sul suo 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); 
    }); 
} 

tuttavia, poiché il thread principale Dart è di per sé un isolato è possibile inviare i dati ad esso utilizzando la porta globale funzione:

#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 ci sono certi limiti su ciò che può essere rispedire e tra gli isolati e attualmente anche gli isolati agiscono diversamente in JS e sulla VM. Le attuali limitazioni sono ben descritte here.

+0

Ma che cosa è se voglio che il mio isolato per generare/aggiornamento? Come un motore di gioco. Presumibilmente esegue tutti i calcoli e passa gli stati aggiornati dell'oggetto in-game. C'è un meccanismo efficiente per questo o devo costruirlo sopra gli isolati? – Pijusn

+0

@Pius non è possibile inviare riferimenti in un isolato, tutti i dati elaborati vengono copiati come descritto qui http://api.dartlang.org/dart_isolate/SendPort.html#send –

+0

Non sto parlando di riferimenti. Sto parlando di dati. Hai mai lavorato con i Web Worker in JavaScript? È possibile inviare dati dal lavoratore in qualsiasi momento. E tanto quanto vuoi. Il lavoratore può lavorare e inviare dati senza nemmeno ascoltare il thread principale mentre il thread principale potrebbe semplicemente ricevere dati utilizzando una funzione di callback. Sto parlando della funzione self.postMessage equivalente in isolare. – Pijusn

0

È ora possibile utilizzare la classe MessageBox per comunicare viceversa. Questo codice invia un messaggio dal codice Isola non appena riceve la fine del sink del MessageBox. Il thread principale riceve i messaggi inviati da Isolate e lo stampa sulla console di Dartium. Una volta ricevuto il lavandino è possibile avviare la logica di gioco e inviare gli aggiornamenti utilizzando l'oggetto sink ricevuto.

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

Come di Dart 1.0, è possibile utilizzare gli isolati come questo:

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

Ecco un esempio in cui genitore crea due isolati e poi due isolati anche parlare gli uni agli altri con il processo padre.

Codice principale: Codice

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

Bambini: Codice

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: dati

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

Il codice precedente funziona con dart sdk versione 1.14.2 e su Chrome, Firefox e IE11 – user2569304

Problemi correlati