zipjsでigo-javascriptの辞書を圧縮
この前作ったJavascriptで形態素解析をするプログラム、辞書をダンロードする関係上起動がやたら長い。2回目以降はキャッシュが効くから速いけど、初回だけとはいえ40MBのダウンロードはさすがにでかすぎるよね・・・。
そういうわけで、辞書の圧縮をしてみた。Javascriptだけでzipの解凍をするというのを見つけたので解凍部分はこれで。
https://github.com/hinassan/zipjs
ところが実際試してみると巨大ファイルの展開がうまくいかない。次のところでスタックオーバーフローを起こす。
String.fromCharCode.apply(null, this.data);
不勉強でapplyとかcallとかいうのをこの件で初めて知った。この二つのメソッドは、普通は暗黙的に設定されるthisを明示的に設定するためのもの。たとえば、次のプログラムの各行はすべて同じ動作をする。
"a,b,c".split(','); String.prototype.split.call("a,b,c", ','); String.prototype.split.apply("a,b,c", [',']);
一番上が最も一般的だと思うんだけど、実は他の書き方のシンタックスシュガーみたいなものだったわけですね。
で、最後の方法では引数の受け渡しに配列が使えるから、これを上手く使うと可変長の引数の受け渡しが簡単にかけると。
PythonでいうところのfromCharCode(*data)みたいなことができるわけですね。
で、結局このコードは
fromCharCode(this.data[0], this.data[1], this.data[2], ... , this.data[this.data.length-1]);
と同じことをしているわけで、this.dataの中身を全部スタックに積んでしまうから馬鹿でかいデータではスタックが溢れてしまったようです。
シンプルに書けてかっこいいんだけど、扱えるデータサイズに限度があるし、実は素直にループで書いたほうが早かったりするので使い所は慎重に選びましょう。
単純にループを回してもいいんだけど、そもそも文字列変換ってオーバヘッドになるよね。
最近のブラウザではTypedArrayという高速な配列が使えるというのでこれを使って書きなおしてみた。
https://github.com/shogo82148/zipjs
あとからTypedArrayを使って機能も豊富な jsziptools っていうのを見つけたんだけど、TypedArray版zipjsのほうが高速になったので、辞書の解凍にはzipjsを使うことにした。手元でunzipコマンド叩いたときの5割増くらいで解凍できたので割りと高速なのでは。
このzipjsを組み込んだigo-javascriptをgithubのほうに上げておきました。
http://shogo82148.github.com/igo-javascript/
解凍を高速化したとはいえ40MBものデータの解凍には5,6秒かかってしまうので、WebWorkerを使って並列処理してます。
初回起動は速くなったかな?
しかし、今度は2回目以降の起動が・・・