Hack と PHP の実行速度の比較
Facebook によって開発されたプログラミング言語 Hack を試してみました。公式サイトはこちらです。
まず、手元の環境に Hack をインストールします。今回は、新たに Ubuntu Server 13.10 の環境を作成してインストールすることにしました。下記のウェブページにある "For Ubuntu 13.10:" の記載のとおりに特に問題なくインストールできました。
最初に Hello world を試してみます。以下のような hello.hh を作成します。普通の PHP のコードを書いて先頭を <?hh に変更するだけです。
<?hh print "Hello, world!\n";
このプログラムを HHVM で実行します。正しく実行されました。
$ hhvm hello.hh Hello, world!
次に、PHP と Hack の実行速度を比較してみます。Hack の最大の特徴は PHP に型アノテーションを持たせたところだと思いますので、その効果を確認するための例題として、以前に下記の記事で試したプログラムを利用することにします。
データを正しい型で扱うことによる高速化 - y_uti のブログ
PHP のプログラムは以下のとおりです (prog1.php 再掲)。
<?php $arr = array(); while ($line = fgets(STDIN)) { $arr[] = trim($line); } $len = count($arr); $result = 0; for ($i = 0; $i < $len; $i++) { for ($j = 0; $j < $len; $j++) { $result -= $arr[$i] + $arr[$j]; } } print $result . "\n";
ランダムな 5000 行のファイルを作って PHP で実行した結果が以下になります。
$ for i in `seq 5000`; do echo $RANDOM; done >a.txt $ time php prog1.php <a.txt -817061200000 real 0m5.740s user 0m5.727s sys 0m0.005s
まずは、これをこのまま Hack プログラムに書き換えて実行してみます。なんと PHP の 2 倍以上の時間がかかってしまいました。
$ time hhvm prog1.hh <a.txt -817061200000 real 0m11.774s user 0m11.706s sys 0m0.052s
これは、prog1.hh の変数がすべてグローバル変数であることが理由だと考えられます。HHVM は型情報を用いた最適化によってプログラムを高速に実行するということですが、グローバル変数の型は決められないので、最適化の効果が得られないのでしょう。
このことを確かめるため、prog1.hh の全体を関数に入れた形にプログラムを書き直して、実行してみます (prog1b.hh)。
<?hh function main() { $arr = array(); while ($line = fgets(STDIN)) { $arr[] = trim($line); } $len = count($arr); $result = 0; for ($i = 0; $i < $len; $i++) { for ($j = 0; $j < $len; $j++) { $result -= $arr[$i] + $arr[$j]; } } print $result . "\n"; } main();
実行結果は以下のとおりです。予想どおり、prog1.hh と比べて実行時間が大幅に短縮されました。
$ time hhvm prog1b.hh <a.txt -817061200000 real 0m4.244s user 0m4.107s sys 0m0.130s
念のため、PHP ではこのような差が出ないということも確認しておきます。実行例の prog1b.php は prog1b.hh の先頭行を <?php に変えたものです。
$ time php prog1b.php <a.txt -817061200000 real 0m5.484s user 0m5.466s sys 0m0.008s
以前の記事では、読み込んだデータを intval で整数にしてから $arr に格納することで、プログラム後半の加算を高速化できることを示しました。prog1b.php を以下のように書き換えて、このことを改めて確認します。
$ diff prog1b.php prog2.php 5c5 < $arr[] = trim($line); --- > $arr[] = intval(trim($line));
$arr の各要素には intval で変換済みの整数値が格納されているので、加算のたびに値を文字列から整数に変換する処理が不要となり、高速に実行できるようになります。実行時間を prog1b.php の半分くらいに短縮できています。
$ time php prog2.php <a.txt -817061200000 real 0m2.686s user 0m2.682s sys 0m0.000s
prog2.php と同じ内容を Hack で書いて実行した結果は以下のとおりです。PHP よりも劇的な効果があるようで、実行時間は prog1b.hh の 15% 程度になりました。まだ HHVM のソースコードを追っていないので推測でしかないのですが、Hack では、型推論によって $arr が array<int> であることが静的にわかっているので*1、実行時の型チェックが不要になり*2、このように高速に実行できるのだと思います。
$ time hhvm prog2.hh <a.txt -817061200000 real 0m0.664s user 0m0.378s sys 0m0.278s