MAX2011

Adobe MAX 2011レポート:Flashランタイムの並行処理

Adobe MAX 2011から「Concurrency in Flash Runtimes」のセッションレポートです。
このセッションのテーマは、Concurrency(コンカレンシー)です。単語としては同時性とか、並行性とかいう意味になります。
Flashは、XMLを解析したり、大きな画像をデコードする処理を行うと、「うっ」と止まってしまいます。これはなんとかならないものかと思いますよね。
スマートフォンでも4コア、2.5GHzのプロセッサが登場する時代に、Flashはまだ同時に1つのことしかできません。重い処理が始まったらそれが終わるまで待たなくてはいけないのです。ところが今日、これを解決する具体的な発表がありました。Flashでも並行処理が行えるようにしようという計画です。未来のFlashのマルチコアアーキテクチャはどのようになるのでしょうか。
以下は全然説明が足りませんが、速報としてお伝えします。

並行処理とは

例えば次のようなFlashがあるとします。

象の絵はずっとアニメーションを続けていますが、大きな背景画像を読み込もうとすると、デコード処理で止まってしまいます。デコードが終わり画像が表示されると、再びアニメーションがはじまります。非常によく体験することですね。ところが未来のFlashでは、デコード処理をバックグラウンドのスレッドで非同期(async image decoding)で行えるようになります。実際に、まったくひっかかりのない様子がデモされました。会場に大きな拍手が起こります。
現在は、レンダリング、I/O(ファイル、DB、ネットワーキング、ソケット)、および画像のデコードが非同期で行えるレベルにあるということです。
非同期のActionScript APIは、
1. ActionScript Request
2. Create Thread
3. Process Request
4. Send Response
5. Dipatch Event
という順序で進みます。
並行レンダリングは、CPUが複数ある場合に、フィルター、Bitblts(bit block transfer)、およびレンダリングに対して行われます。
将来はAsync JSON、Async XML、Background JITも予定されているそうです。
しかしこれで十分といえるでしょうか。
・待ち時間の長い処理(ストラテジーアルゴリズム、物理エンジンなど)
・実行時間の長い処理(PDFの生成、画像処理など)
についてはまだ解決できません。

ActionScript Worker

そこで登場するのが、ActionScript Workers(ワーカー)です。ワーカーというのは、メインの処理とは別に動作するプロセスのことです。ワーカーに仕事を任せることで、メインとは別の処理を「並行して」行うことができます。
なお、専門的な話になりますが、ActionScriptワーカーの特徴は、「何も共有しない(shared nothing)」ということです。
さて、例えば地図で移動経路を検索するとします。ワーカーを使わない場合は、検索している間はFlashが固まったように見え、地図をスクロールさせることはできませんが、ワーカーに検索をやらせれば、検索している間も地図のスムーズなスクロールが可能です。

ActionScript Workerのライフサイクル

ワーカーの作成(creating workers)

var domain:WorkerDomain = WorkerDomain.current;
var url:URLRequest = new URLRequest("abc.swf");
var worker:Worker = domain.createWorkerFromURL(url);

ワーカーの開始と終了(starting & stopping)

var toplevel:Promise = worker.start();
...
var wasRunning:Boolean = worker.stop();

ワーカーのステート(worker states)

NEW → STARTING → RUNNING → FINISHING → STOPPEDと遷移します。

ドメイン

ワーカーの作成

var domain:WorkerDomain = WorkerDomain.current;
domain.createWorkerFromURLRequest(url);
domain.createWorkerFromByteArray(bytes);
domain.createWorkerFromWorker(worker);
domain.createWorkerFromMain();

コミュニケーション

プロミス

プロミスは、ワーカーのアドレス空間にあるオブジェクトのローカル表現です。
(Local Representation of an object residing in a worker’s address space.)

var toplevel:Promise = worker.start();
toplevel.foo.bar();
// worker code
package foo
{
public function bar():void
{
trace("bar");
}
}

リモートメソッドの呼び出し(remote method invocation)

var barResult:Promise = toplevel.foo.bar();
// worker code
package foo
{
public function bar():String
{
return "bar";
}
}

プロミスを利用してこのように書きます。イベントみたいなものですかね。

var barResult:Promise = toplevel.foo.bar();
// async
barResult.local::when(function(result:Promise)):void
{
trace(result.local::receive());
});
// sync
var value:String = String(barResult.local::receive());

引き数の渡し方

var baz:Promise = worker.start();
baz.foo(myObject);
// worker code
public function foo(value:MyObject):void
{
trace(value.name);
}

ものすごく大きなデータが渡されることを想定して、プロミスを利用してこのように書きます。

var bar:Promise = Primise.wrap(largeObj);
var baz:Promise = worker.start();
baz.foo(bar);
// worker code
public function foo(value:Promise):void
{
var largeObj:Object = value.local::receive();
...
}

パイプライン

var baz:Promise = worker.start();
baz.foo();
baz.bar();
baz.foobar("baz");

レンダリング

構造としては、コンテナの上にMainを含む複数のランタイムインスタンスがあって、Shared Display(共有表示オブジェクト)があります。複雑な計算を伴うものを表示をしようとする場合、ワーカーを使わないとフレームレートがガクンと落ちる瞬間がありますが、ワーカーを使ってバックグラウンドレンダリングを行えばフレームレートは落ちません。

WorkerView

var view:WorkerView = worker.view;
view.viewport = new Rectangle(0, 0, width, height);
addChild(view);

セキュリティ制約

Mainと各ワーカーは同じドメインにある必要があります。
セッションで紹介されたのはPre-Alpha版という、開発のごく初期段階のもので、Flash Player 12に搭載されるかどうか分かりません。しかしこれはStage 3Dと並んで、Flash Playerの非常に大きな進化をもたらす技術であると感じました。


Author

  • Shuichi Ishikawa
    Shuichi IshikawaShuichi
    Ishikawa
  • MikasaHideyuki
    Hideyuki MikasaHideyuki
    Mikasa
Shuichi Ishikawa
執行役員/インタラクションデザイングループ

フロントエンド開発からクラウドサーバー構築まで、新しいことに興味がありすぎて時間が足りない制作部門リーダー。Adobeインフルエンサー。九州芸術工科大学→ドリームキャスト→サーバーサイド→フロントエンド→執行役員→早稲田大学大学院→Kinect v2

好きな飛行機
B787-8
好きな空港
SXM
好きな航空路
Y28
Hideyuki Mikasa
オーサリングエンジニア

mikasa's text