正規表現のベンチマーク(String.match と RegExp.exec のざっくりとした違い)
2009-01-12追記 タイトル修正しました。
2009-01-14追記 String.indexOf と RegExp.test のスコアが逆に書かれてていたのを修正しました。
String.match ばかりで、RegExp.exec を使ったことがありませんでした。
ちょっと気になったので色々とベンチマークを取ってみました。
TEST | TIMES | IE6 | Fx3.0 | Fx3.1 (JIT) |
Safari3 | Chrome1 (JIT) |
---|---|---|---|---|---|---|
A. match(/\s*/) vs match(/ */) |
||||||
"aaaaaaaaaaaa".match(/\s*aa\s*/) | 1000000 | 7203 | 1714 | 327 | 2375 | 2128 |
"aaaaaaaaaaaa".match(/ *aa */) | 1000000 | 7156 | 1638 | 297 | 2328 | 2148 |
B. RegExp.exec vs RegExp.test |
||||||
/\s*aa\s*/.exec("aaaaaaaaaaaa") | 1000000 | 6860 | 4096 | 3095 | 2265 | 1939 |
/\s*aa\s*/.test("aaaaaaaaaaaa") | 1000000 | 2094 | 1506 | 345 | 875 | 2050 |
C. String.match vs RegExp.exec |
||||||
"aaaaaaaaaaaa".match(/^aaaaaaa$/) | 1000000 | 2031 | 1807 | 438 | 1453 | 669 |
/^aaaaaaa$/.exec("aaaaaaaaaaaa") | 1000000 | 1797 | 1688 | 701 | 1437 | 543 |
D. String.match vs RegExp.exec (global match) |
||||||
"aaaaaaaaaaaa".match(/aa/g) | 1000000 | 13422 | 11773 | 5264 | 4048 | 4969 |
/aa/g.exec("aaaaaaaaaaaa") | 1000000 | 5969 | 3761 | 2480 | 1953 | 1338 |
E. String.indexOf vs RegExp.test |
TIMES | IE6 | Fx3.0 | Fx3.1 (JIT) |
Safari3 | Chrome1 (JIT) |
---|---|---|---|---|---|---|
"E, F, G".indexOf(",") >= 0 | 1000000 | 4468 | 1640 | 241 | 922 | 1418 |
/,/.test("E, F, G") | 1000000 | 2109 | 484 | 648 | 656 | 223 |
TEST E. String.indexOf vs RegExp.test (TIMES 1000000)
IE6 | IE7 | IE8β2 | Firefox2.0 | Firefox3.0 | Firefox3.1(JIT) | |
---|---|---|---|---|---|---|
String.indexOf | 2109 | 3604 | 1076 | 969 | 490 | 608 |
RegExp.test | 4484 | 5148 | 3822 | 2266 | 1606 | 203 |
Safari3 | Chrome1(JIT) | Opera9.27 | Opera9.62 | Opera10α | ||
String.indexOf | 625 | 216 | 2843 | 1250 | 1265 | |
RegExp.test | 891 | 1148 | 3938 | 1891 | 2313 |
TEST E. はこちらでテストできます。
- http://pigs.sourceforge.jp/blog/200901140208/String.indexOf.htm
- http://pigs.sourceforge.jp/blog/200901140208/RegExp.test.htm
ソースはこうなっています。
<html><head><title></title></head><body><script> function boot() { job(1000000); } function job(times) { var begin = +new Date; while (times--) { "E, F, G".indexOf(",") >= 0; // String.indexOf または /,/.test("E, F, G"); // RegExp.test } alert(+new Date - begin); } window.onload = boot; </script></body></html>
グローバルマッチだと、 exec は match の3倍速? びっくりですね。
あと、String.indexOf より RegExp.test が2〜4倍速なのは想定外でした。
ごく一部の例外を除いて、String.indexOf は RegExp.test よりも高速です。修正後の表を追加しました。大変お騒がせしました。
for と while ループの比較
普通は for ループを使いますが、特定条件下では while ループのほうが15%ほど高速でした。
ただし、以下の条件をクリアする必要があります。
- 条件
- 配列の中身が連続している(欠落[delete]していないこと)
- 各要素が false として評価されないことを保障できる
CSSセレクタのフィルタリングループなんかに適用すると速くなるかもしれませんね。
// 配列の仕込み var ary = Array(100000); var i = 0, iz = ary.length; for (; i < iz; ++i) { ary[i] = i + 1; } ary_for(ary, 100); ary_while(ary, 100); function ary_for(ary, times) { var n = 0, v, i = 0, iz = ary.length; var begin = +new Date; while (times--) { i = 0; for (; i < iz; ++i) { // 違いはここと v = ary[i]; n += v; } } alert("for vs while = " + (+new Date - begin)); } function ary_while(ary, times) { var n = 0, v, i = 0, iz = ary.length; var begin = +new Date; while (times--) { i = 0; while ( (v = ary[i++]) ) { // ここ n += v; } } alert("for vs while = " + (+new Date - begin)); }
TEST | TIMES | IE6 | Fx3.0 | Fx3.1(JIT) | Safari3 | Chrome1(JIT) | |
---|---|---|---|---|---|---|---|
F. for vs while |
|||||||
ary_for(ary, 100) | 100 | 10062 | 3701 | 325 | 4109 | 328 | |
ary_while(ary, 100) | 100 | 8625 | 2798 | 400 | 3312 | 307 |
反省会
- やれやれ、またお直しですか。