ActionScript Worker (Flash Player マルチスレッド) [Flex]
Flash Builder4.7+Apache Flex4.9+FP11.4でマルチスレッドを試してみた。
Music Playerのスペクトラムイコライザーの計算部分を別スレッドにしてみた。
Flash BuilderでまずFlexプロジェクトを作成する。
次にファイル−新規−ActionScriptワーカで子スレッド用クラスを作成する。
このときに子スレッドとのやり取りするWorkersクラスが自動で作成される。
こちらが子スレッドとして動作するMuWorkerクラス
上記子スレッドのクラスを作成すると以下のWorkersクラスファイルが作成されます。
必要な処理を追記します。
あとは、必要な処理をメインクラスにWorkersクラスをコントロールする処理を追加。
コンパイルは、オプションに-swf-version=17を追加してコンパイル。
子スレッドで他にいくつか処理をやってみたが使えるものが限定されるもよう。
サーバとのやり取りをすると今まで出なかったクロスドメインセキュリティの
エラーがでてしまう。
コントロールできるサーバはcrossdomain.xmlを作成して対処したが
YouTube APIはcrossdomain.xmlが読めてもAPIが拒否されてしまう。
もうちょとよく見ないと・・・
単純な負荷がかかる計算処理などは子スレッドに任せるのはできそう。
あとは通信系が子スレッドにもっていけるといいのになぁ
今回はActionScriptマルチスレッドの仕様よくみないでヘルプのサンプルみて作成。
シリアライズとかJavaでのスレッド鉄則の7パターンでのクラス作成みたいなことは
考えないで単純なやり方で実装。
マルチスレッドは非同期なので乱用は注意しないとね。
Music Playerのスペクトラムイコライザーの計算部分を別スレッドにしてみた。
Flash BuilderでまずFlexプロジェクトを作成する。
次にファイル−新規−ActionScriptワーカで子スレッド用クラスを作成する。
このときに子スレッドとのやり取りするWorkersクラスが自動で作成される。
こちらが子スレッドとして動作するMuWorkerクラス
package info.akiboi.worker { import flash.display.Sprite; import flash.events.Event; import flash.system.MessageChannel; import flash.system.Worker; : public class MuWorker extends Sprite { private var commandChannel:MessageChannel; private var resultChannel:MessageChannel; private var _snd:SoundData; public function MuWorker() { super(); initialize(); } private function initialize():void { // Get the MessageChannel objects to use for communicating between workers // This one is for receiving messages from the parent worker commandChannel = Worker.current.getSharedProperty("incomingCommandChannel") as MessageChannel; commandChannel.addEventListener(Event.CHANNEL_MESSAGE, handleCommandMessage); resultChannel = Worker.current.getSharedProperty("resultChannel") as MessageChannel; : } private function handleCommandMessage(event:Event):void { if (!commandChannel.messageAvailable) return; //Objectでメインスレッドからのメッセージを受け取とる var obj:Object = commandChannel.receive() as Object; //子スレッド処理 : //子スレッド処理終了したらメインスレッドにメッセージを送る result:Object = new Object(); : resultChannel.send(result); } } } }
上記子スレッドのクラスを作成すると以下のWorkersクラスファイルが作成されます。
必要な処理を追記します。
package { import flash.events.Event; import flash.system.MessageChannel; import flash.system.Worker; import flash.system.WorkerDomain; import flash.system.WorkerState; : public class Workers { private var bgWorker:Worker; private var bgWorkerCommandChannel:MessageChannel; private var resultChannel:MessageChannel; : public function Workers() { initialize(); } //子スレッド、メッセージのチャンネル作成して子スレッド起動 private function initialize():void { // Register the alias so we can pass CountResult objects between workers // Create the background worker bgWorker = WorkerDomain.current.createWorker(info_akiboi_worker_MuWorker); // Set up the MessageChannels for communication between workers bgWorkerCommandChannel = Worker.current.createMessageChannel(bgWorker); bgWorker.setSharedProperty("incomingCommandChannel", bgWorkerCommandChannel); resultChannel = bgWorker.createMessageChannel(Worker.current); resultChannel.addEventListener(Event.CHANNEL_MESSAGE, handleResultMessage); bgWorker.setSharedProperty("resultChannel", resultChannel); // Start the worker bgWorker.addEventListener(Event.WORKER_STATE, handleBGWorkerStateChange); bgWorker.start(); } //メインタスクからの子スレッドにメッセージ送信するメソッド` // Main -> Workders -> 子レッド public function sendMessage(obj:Object):void { bgWorkerCommandChannel.send(obj); } //子スレッドのステータスをリスナしておきここで受け取る private function handleBGWorkerStateChange(event:Event):void { if (bgWorker.state == WorkerState.RUNNING) { //例 子スレッドが準備できたことをカスタムdispatcherでMainに通知している例 _dispatcher.muWorkerAPI(EventConst.WORKER_READY,"",true,null); } } //子スレッドからメッセージが送信されたら行う処理 private function handleResultMessage(e:Event):void { //子スレッドからresultChannelを通して結果を受け取る。 var result:Object = resultChannel.receive() ; //例 子スレッドから結果をカスタムdispatcherを使ってMainに返す _dispatcher.muWorkerAPI(result.action,result.msg,result.err,result.obj); } //FBでActionScriptワーカクラスを作成するとこのWorkersクラスが自動作成され、以下のようなマッピング情報が書き込まれます。 [Embed(source="../workerswfs/info/akiboi/worker/MuWorker.swf", mimeType="application/octet-stream")] private static var info_akiboi_worker_MuWorker_ByteClass:Class; public static function get info_akiboi_worker_MuWorker():ByteArray { return new info_akiboi_worker_MuWorker_ByteClass(); } } }
あとは、必要な処理をメインクラスにWorkersクラスをコントロールする処理を追加。
コンパイルは、オプションに-swf-version=17を追加してコンパイル。
子スレッドで他にいくつか処理をやってみたが使えるものが限定されるもよう。
サーバとのやり取りをすると今まで出なかったクロスドメインセキュリティの
エラーがでてしまう。
コントロールできるサーバはcrossdomain.xmlを作成して対処したが
YouTube APIはcrossdomain.xmlが読めてもAPIが拒否されてしまう。
もうちょとよく見ないと・・・
単純な負荷がかかる計算処理などは子スレッドに任せるのはできそう。
あとは通信系が子スレッドにもっていけるといいのになぁ
今回はActionScriptマルチスレッドの仕様よくみないでヘルプのサンプルみて作成。
シリアライズとかJavaでのスレッド鉄則の7パターンでのクラス作成みたいなことは
考えないで単純なやり方で実装。
マルチスレッドは非同期なので乱用は注意しないとね。