2012年4月7日土曜日

WebWorkerはJSの救世主となれるのか?

「JavaScriptはシングルスレッドしか扱えない」というのは、JavaScriptをいじったことがある人には馴染み深い定説でしょう。一見するとsetIntervalやsetTimeoutなどでマルチスレッドな作業がこなせるように見えるJSですが、実はあれはそれらの関数に渡したコールバックオブジェクトをキューに追加しておいて今実行している関数を抜けたらそのキューから次の関数を呼び出すという実装をしているだけなのです。

そんなJavaScriptですが、コーディングしてChromeやSafariなどでWebInspectorを開いてデバッグをしているとグローバルスコープに気になるオブジェクトを見かけることがあります。
Workerとあります。みなさんもC++などでマルチスレッドなプログラムを組んだり、GUIつきのプログラムを書いているときに「ワーカースレッド」という言葉を耳にしたことはないでしょうか。このWorkerがその「ワーカー」と同じなら、何やらマルチスレッドできそうな「匂い」を感じませんか?感じますよね?
そう、このWorkerコンストラクタこそ、我らがJavaScripterの救世主(になる予定)のマルチスレッド化の秘密兵器なのです。
さて、そんなWorkerオブジェクトですが、一体どうやって使うんでしょうか。結論から言ってしまうと次のように書けば使えます。
//main.js
var worker = new Worker("calc.js");    //Workerの処理を記述したファイルのパスを引数にコンストラクタを呼び出す

worker.onmessage = function(event){    //Workerからメッセージが返ってきた時の処理を設定する
   var data = event.data;
   data.forEach(function(num){
      write(num + ", ");
   });
};

var defs = {a_n : [0, 1], to : 20};
worker.postMessage(defs);               //Workerにデータを渡して処理を開始させる
//calc.js
onmessage = function(event){            //メインスレッドからデータを受け取って処理する
   var data = event.data, results = [data.a_n[0], data.a_n[1]];
   for(var i = 0; i < data.to; ++i){ //フィボナッチ数列を計算して配列に収める
      results.push(results[i] + results[i + 1]);
   }
   postMessage(results);                //処理した結果をメインスレッドに返す
};
WebWorkerを使うには最低限.jsファイルが2つ必要です。一つは、Workerを呼び出すメインのファイル(上記の例のmain.jsに当たります)、もうひとつはWorkerがすべき処理を記述したファイル(上記の例でのcalc.js)です。大まかな流れはコメントに書いてあるとおりなので、詳しい解説は不要でしょう。
しかし、その中でも注意すべき点が2つあります。まず、calc.js内のonmessage関数の定義の部分に注目してください。まるでグローバル変数のような定義をしていますが、これはWorkerのスコープとメインスレッドのスコープが分離しているためです。つまり、このonmessage変数はメインスレッドからは参照不可能なわけです。
またこれに伴って通常、ユーザーエージェントでJavaScriptを実行するとグローバルスコープにwindowやDOMなどのオブジェクトが定義されているものですが、Workerが動作するスコープにはこれらのオブジェクトは一切定義されていません。そのため、WorkerからDOM操作などはできません。これは、自らGUIつきのプログラムを書いたことがある人はよく解ると思いますが、好き勝手にGUIをいじるコードを書いていると複数のスレッドが同時にGUIをいじってしまって整合性に破綻をきたしてしまう場合があるので、メインスレッド以外からは一切GUIをいじれないようにするための措置です。
2つ目は、メインスレッドとWorkerでやり取りされるデータの形式です。この二者間のデータのやり取りは、JSON形式でやり取りされているようなので関数を含むオブジェクトをpostMessageに渡すと関数が失われてしまいます。このため、メソッドによる振る舞いの定義が必要なオブジェクトを扱う処理をWorkerでこなすには少し手を加える必要があります。
以上、自サイトで公開しているプログラム内でWebWorkerを使う機会があったので、備忘録も兼ねて記事にしてみました。



後日追記:もうちょっと実用的なサンプルをjsdo.itに公開しました。

2012年4月4日水曜日

おすすめのIDE

本格的な記事の投稿テストも兼ねて今回は、最近自分が愛用しているIDEを紹介したいと思います。
その名も「Cloud9 IDE」です。
「名は体をあらわす」とはよく言ったもので、このツールは名前の通りクラウド上で使えるIDEなのです。つまり、ブラウザ上でソースコードの編集からデバッグまでこなせてしまうわけです。(もっともbuiltinのデバッガーはNode.jsを使ったコードにしか使えませんけどね)
投稿のテストも兼ねて以下にCloud9IDEの紹介動画を貼りつけておきます。


このCloud9IDEはクラウド上で使うのが筋なんですが、実を言うとローカル環境で動かすことも出来ます。(ただし若干めんどくさいです。それに今のところWindowsじゃうまくいってません)
そこで今回は比較的簡単に構築できるUbuntu上での方法を軽く紹介したいと思います。まず、必要なものはソースコードを落とすのとセットアップのシェルスクリプトが使用するgitだけです。あと、できればNode.jsのパッケージ管理ソフトのnpmとそれを使うのに必要なcurlもインストールしておくべきなのですが、これらはたぶん、シェルスクリプトを起動したら勝手に入ると思います。(自分はその前にインストールしてあったのでわからない^^;)

必要なものをSynapticでインストールしたらまずは、ソースコードを落としてきます。
   $ git clone git://github.com/ajaxorg/cloud9.git

そうしたら次にカレントディレクトリをcloud9/binに移してcloud9.shというシェルスクリプトを起動します。
   $ cd cloud9/bin
   $ ./cloud9.sh

これだけでおしまいです。あとはしばらく待っていれば、勝手にスクリプトが必要なサブモジュールを拾ってきてくれてブラウザ上にCloud9IDEのウェルカムページを表示してくれるはずです。いや〜、実に簡単ですね。
うまく動かない場合はcloud9にカレントディレクトリを移して
   $ git submodule update --init --recursive

とかやるとうまく行くかも。なんて無責任な…

ちなみにcloud9.shにはいくつかオプションが渡せます。
まず-wはワークスペースとして使用するディレクトリを指定します。デフォルトではcloud9のルートディレクトリになっています。
-pはポート番号を指定します。デフォルトは3000です。
-dはデバッグモードでcloud9IDEを起動します。デバッグモードだとIDE自体のログがブラウザのコンソールに出力されます。
よく使いそうなものはこのくらいですかね。

正直なところCloud9IDEの日本語サポートは全くと言ってなされていません。事実、htmlエディター以外ではIMEからのインプットが処理されてないらしく、変換を確定するまでテキストが表示されません。
おまけに半角文字を使用するとカーソルの位置がおかしくなります^^;
さらには唯一IMEからのインプットが処理されているhtmlエディターでさえ変換中のテキストが明後日の方向に表示される始末…

ですが、Cloud9IDEが素晴らしいツールであることには変わりありません。Node.jsの開発のデファクトスタンダードになる可能性だって大いにあります。
さああなたも、Cloud9IDEでよいプログラミングライフを。

2012年4月3日火曜日

ブログ始めてみました

いやあ、春ですね〜。なにか新しいことを始めたくなる季節ですよね〜。
というわけでどうも、はざまと申します。以後お見知りおきを。

初回の投稿なので、軽く自己紹介でもしましょうか。
名前は最初に述べたのでいいとして、こちらのブログでは主にWeb(基本的にJavaScriptによるプログラミング。もしかしたらそれに関連してHTML5などの周辺技術も)とNative(ネイティブ環境で動作するプログラミング言語。主にC++)をテーマにこれら言語の仕様やこれらの言語でプログラミングしていて思ったこと、つまづいたこと、使ってみて自分が素晴らしいと思った技術のメモ、別途公開している自作プログラムの解説、製作日記などを綴っていこうと思っています。
よろしくお願いしますm(__)m