忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

DartのIsolateを使う その3

前回までは不必要な要素をなるべく剥ぎとってわかりやすくしたデモといった感じでした。
今回は、アニメーションをするときにIsolateを使うことを考えます。


プログラム

isolatetest.dart

import "dart:isolate";
import "dart:async";
import "dart:html";

class Calculator{
  SendPort sendPort = null;
  ReceivePort fromSubIsolate;
  int counter = 0;
  int result = 0;
  
  Completer _onInitController = new Completer();
  Future get onInit => _onInitController.future;
  
  Completer _onUpdateController = new Completer();
  Future get onUpdate => _onUpdateController.future;
    
  Calculator(){

    fromSubIsolate = new ReceivePort();
    Isolate.spawnUri(
        new Uri.file("subIsolate.dart"), 
        [],
        fromSubIsolate.sendPort);
  
    
    fromSubIsolate.listen((message){
      if(message is SendPort){
        sendPort = message;
        _onInitController.complete();
      }
      if(message is int){
        result = message;
        _onUpdateController.complete();
      }
    });
  }
  
  void beginUpdate(){
    _onUpdateController = new Completer();
  }
  
  void update(){
    counter++;
    sendPort.send([counter, 2]);
  }
}

List<Calculator> calculators = new List<Calculator>();

void main() {
  for(var i = 0; i < 10; i++){
    var calculator = new Calculator();
    calculators.add(calculator);
  }
  
  Future.wait(calculators.map((c)=>c.onInit).toList()).then((_){
    animate(0.0);
  });
}

void animate(double deltaTime){
  print("beginUpdate");
  
  for(var calculator in calculators){
    calculator.beginUpdate();
  }
  
  print("update");
  
  for(var calculator in calculators){
    calculator.update();
  }
  
  Future.wait(calculators.map((c)=>c.onUpdate).toList())
  .then((_){
    print("print");
    
    for(var calculator in calculators){
      print("${calculator.counter}, ${calculator.result}");
    }
  })
  .then((_){
    window.animationFrame.then(animate);
  });
}

subIsolate.dart

import "dart:isolate";

void main(List<String> args, SendPort sendPort){
  ReceivePort fromMainIsolate = new ReceivePort();
  sendPort.send(fromMainIsolate.sendPort);
  fromMainIsolate.listen((message){
    List<int> parameters = message;
    sendPort.send(parameters.reduce((a, b) => a + b));
  });
}

結果

beginUpdate
update
print
1, 3
1, 3
1, 3
1, 3
1, 3
1, 3
1, 3
1, 3
1, 3
1, 3
beginUpdate
update
print
2, 4
2, 4
2, 4
2, 4
2, 4
2, 4
2, 4
2, 4
2, 4
2, 4
beginUpdate
update
print
3, 5
3, 5
3, 5
3, 5
3, 5
3, 5
3, 5
3, 5
3, 5
3, 5
..

解説

このプログラムはゲームでIsolateを使うことを想定しています。
window.animationFrameを使っているので、おそらく一秒に数十回animateメソッドが呼ばれています。
つまり一秒に数十回子Isolateと通信をして、計算結果をもらっているのです。

それだけでなく、Isolateを10個も作ってそれらを並列に動かしています。

「結果」のところを見て下さい。
「1, 3」という数字がたくさん(10個)表示されていますね。
これは各Isolateが1に2を足した結果3を出したということを意味しています。

次のanimateの呼び出しでは、2に2を足して4を出しています。
その次には3に2を足して5です。

まあともかく、重要なのは一秒間に何回もIsolateと通信して計算させている、という点です。
これでもうゲームで並列処理は簡単ですね!

拍手[0回]

PR