2012年2月11日

JavaScript whileループとPot.Deferred.forEverイテレータでCPU使用率を比較-Pot.js+PotLite.jsリリースノート

Pot.js 1.13PotLite.js 1.30 リリースしました。

Pot.js 1.13 と PotLite.js 1.30 では、主に内部ループ処理を大幅に高速化しました。
(そろそろ ChangeLog 作らないとまずいかも…)

あとは、変数宣言とか 例の (function(){}()) とか (結局直してる)
細かい修正などです。

先日、Hacker NewsEcho JS で Pot.js が紹介されました (ありがとうございます)。
でもアクセスが今までの 1000 倍くらいになって、すごいことになってちょっとビビった。
(API サーバのほうは適当に調節しておいたので大丈夫だった。よかった。。)


それで Pot.js の本来の存在意義ですが、

実行環境の CPU に負荷をかけることなく JavaScript が実行できる。

といったことが本来の目的であり、常に追求している目標でもあります。
Deferred が重点にとらわれがちですが、Pot.Deferred はそれの足がかりであり、
Pot.Deferred だけがライブラリの中核ではないので、いろいろ使ってみてください。

新しいデザインのリファレンス

現在、新しいデザインでリファレンスを書き直しています。


前は 全部で 1 ファイルになっちゃってて、どんどん重くなるし更新もやり難くて
どうしようもなかったのですが、今回は 各ページを非同期読み込みにして
英語版と日本語版で見れるようにして、戻るボタンとかも再現したり、がんばってます。

でもまだ作成途中です (2012-02-11 現在)。

ある程度完成したら 本来の /index.html に移動させようと思ってるんですが、
先ほどの Echo JS などが /test-for-new-design/ にリンクしちゃってるもんだから
どうしようかと考え中。(たぶん リダイレクトか、もうこのままでいいか…)。

CPU 比較を実行

jsFiddle のほうで
JavaScript の while ループと、Pot.js の非同期イテレータとで CPU 使用率の比較を書いてみました。
前に書いた Pot.js イテレータと jQuery.each と for ループの CPU 使用率をグラフで比較
と同じ事ですが、実際に実行できます (ただし負荷テストなのでブラウザクラッシュに気をつけてください)。
もっとも最近のブラウザはループでクラッシュしないと思いますが。。

CPU 使用率は、Web ブラウザからの JavaScript では取得できないと思うので、
CPU モニタリングするアプリとか、
なければ Win ならタスクマネージャから「パフォーマンス」→ 「CPU 使用率」
を見ながら実行してみるとわかりやすいと思います。


今回は while 文と Pot.Deferred.forEver の比較ですが、
Pot.js 非同期イテレータは CPU 負荷が一定量に抑えられたループが可能になっていると思います。
ただし、この例のような処理だと実行時間はある程度伸びてしまいます。

実行時間に関しては 速度調整 が可能なので、処理に応じたスピードを選ぶこともできます。
(このへんは今後改善したいです)。

サンプルのソースコード

jsFiddle でも確認できますが、今回使用したサンプルのソースコードです。
ループ処理の部分だけ抽出しています。

JavaScript while ループを使ったソースコード:
  1. // while で同期ループして圧縮  
  2. compressSync : function(s) {  
  3.     var a = 53300, b, c, d, e, f, g = -1,  
  4.         h, i, r = [], x = String.fromCharCode;  
  5.   
  6.     s = new Array(a--).join(' ') + s;  
  7.     while ((b = s.substr(a, 256))) {  
  8.         for (c = 2, i = b.length; c <= i; ++c) {  
  9.             d = s.substring(  
  10.                 a - 52275,  
  11.                 a + c - 1  
  12.             ).lastIndexOf(b.substring(0, c));  
  13.             if (!~d) {  
  14.                 break;  
  15.             }  
  16.             e = d;  
  17.         }  
  18.         if (c === 2 || c === 3 && f === g) {  
  19.             f = g;  
  20.             h = s.charCodeAt(a++);  
  21.             r.push(  
  22.                 x(h >> 8 & 255),  
  23.                 x(h & 255)  
  24.             );  
  25.         } else {  
  26.             r.push(  
  27.                 x((e >> 8 & 255) | 65280),  
  28.                 x(e & 255),  
  29.                 x(c - 3)  
  30.             );  
  31.             a += c - 1;  
  32.         }  
  33.     }  
  34.     return r.join('');  
  35. }  

Pot.js 非同期イテレータ (今回は Pot.Deferred.forEver) を使ったソースコード:
  1. // Pot.js 非同期イテレータで圧縮  
  2. compressAsync : function(s) {  
  3.     var a = 53300, b, c, d, e, f, g = -1,  
  4.         h, i, r = [], x = String.fromCharCode;  
  5.   
  6.     var deferred = new Pot.Deferred();  
  7.   
  8.     s = new Array(a--).join(' ') + s;  
  9.   
  10.     // whileループを forEver に置き換え  
  11.     Pot.Deferred.forEver[SPEED](function() {  
  12.   
  13.         b = s.substr(a, 256);  
  14.         if (!b) {  
  15.             throw Pot.StopIteration;  
  16.         }  
  17.   
  18.         for (c = 2, i = b.length; c <= i; ++c) {  
  19.             d = s.substring(  
  20.                 a - 52275,  
  21.                 a + c - 1  
  22.             ).lastIndexOf(b.substring(0, c));  
  23.             if (!~d) {  
  24.                 break;  
  25.             }  
  26.             e = d;  
  27.         }  
  28.         if (c === 2 || c === 3 && f === g) {  
  29.             f = g;  
  30.             h = s.charCodeAt(a++);  
  31.             r.push(  
  32.                 x(h >> 8 & 255),  
  33.                 x(h & 255)  
  34.             );  
  35.         } else {  
  36.             r.push(  
  37.                 x((e >> 8 & 255) | 65280),  
  38.                 x(e & 255),  
  39.                 x(c - 3)  
  40.             );  
  41.             a += c - 1;  
  42.         }  
  43.     }).then(function() {  
  44.         deferred.begin(r.join(''));  
  45.     }, function(err) {  
  46.         deferred.raise(err);  
  47.     });  
  48.     return deferred;  
  49. }  

同期か非同期かの違いがありますが、
単に、メインの while 文を Pot.Deferred.forEver に変えてるだけです。
forEver は、StopIteration が throw されるまで、永久にループする関数です。

あと、この関数は LZ77アルゴリズムによる圧縮関数をJavaScript最短コードで | 圧縮電子精神音楽浮遊構造体 (見れないかも)
で作ったソースコードをちょっとだけ手直ししたものです。
文字列を圧縮解凍します。

Pot.js / PotLite.js

Pot.js は CPU に負荷をかけることなく JavaScript の実行を可能とするユーティリティライブラリです。

PotLite.js は Pot.js の非同期な部分だけを抽出したライトバージョンです。

ダウンロード

マニュアル

マニュアルは上に書いたように 2012-02-11 現在、まだすべてのオブジェクトの解説ができてません。。

その他の情報についてはマニュアル/マニュアルからのリンク から参照ください。

レポジトリ




その他、なにか問題・バグ・感想・指摘などあれば、
コメントやメールまたは @polygon_planet まで送っていただけるとうれしいです。


0 件のコメント:

コメントを投稿