なでしこの実行速度が話題になっていたので、久々に、手元にあるMacbook Pro(m1)でベンチマークしてみました。なでしこ3のPC版(Node.js版)と各種スクリプト言語を比較してみましょう。
再帰処理フィボナッチ勝負
まずはフィボナッチで試してみましょう。
なでしこ3
なでしこ3.4.24で試してみました。
●FIB(Nの)
もし、N<2ならばNで戻る。
((N-1)のFIB)+((N-2)のFIB)で戻る。
ここまで。
(40のFIB)を表示。
実行してみると、下記のように4秒かかりました。
time cnako3 fib.nako3
102334155
cnako3 fib.nako3 3.94s user 0.05s system 98% cpu 4.078 total
Python3
次に、Python 3.9.7で試してみます。速度には影響しないものの、タイプヒントも付けてみました。
def fib(n:int) -> int:
if n < 2: return n
return fib(n - 2) + fib(n - 1)
print(fib(40))
実行してみましょう。すると、なんと26.4秒かかってしまいました。Python遅いと言われていますが、やはりPython3.9だと再帰のコードが遅いですね。
time python3 fib.py
102334155
python3 fib.py 26.16s user 0.03s system 99% cpu 26.392 total
Perl
次に、Perlで試してみましょう。
sub fib($) {
return $_[0] if ($_[0] < 2);
return fib($_[0] - 2) + fib($_[0] - 1);
}
print fib(40), "\n";
実行してみましょう。36.7秒かかり、Python3以上に遅いことが分かります。
time perl fib.pl
102334155
perl fib.pl 36.48s user 0.02s system 99% cpu 36.719 total
Node.js
次に、なでしこ3のエンジンであるNode.jsで試してみましょう。
function fib(n) {
if (n < 2) return n;
return fib(n - 2) + fib(n - 1);
}
console.log(fib(40));
実行してみましょう。早い!やはり早いです!
time node fib.js
102334155
node fib.js 1.28s user 0.01s system 98% cpu 1.316 total
ここから、なでしこを使うと、コンパイル処理とか、内部で変数チェックとか、余分な処理が走るため、JSの3倍遅くなる事も分かります。
PHP8
次に、PHP8.3.0で試してみましょう。PHP8になり、ずいぶん処理が速くなったと聞いていましたが、どうでしょうか。
<?php
function fib($n) {
if ($n < 2) return $n;
return fib($n - 2) + fib($n - 1);
}
echo fib(40)."\n";
実行してみましょう。9.695秒で、やはり、Node.jsには追いついていません。
time php fib.php
102334155
php fib.php 9.60s user 0.02s system 99% cpu 9.695 total
Ruby
次に、日本発のプログラミング言語のRuby2.6.10p210で試してみましょう。Ruby3でなくてすみません。
def fib(n)
return n if (n < 2)
return fib(n - 2) + fib(n - 1)
end
puts fib(40)
実行してみましょう。13秒です!良い感じです。
time ruby fib.rb
102334155
ruby fib.rb 12.92s user 0.05s system 99% cpu 13.078 total
結果発表
結果をまとめてみました。今回の、スクリプト言語速度対決は、Node.jsが一番速く、実行エンジンとしてNode.jsを使っているなでしこ3がそれに次いで速いという結果になりました。とは言え、どの言語も素晴らしく、速度が遅い部類のPythonが2023年、最も使われています。もはや、PCは十分速くなり、素の実行速度など、それほど気にする必要は無いという時代になっていますね。
順位 | 言語 | 処理時間 |
---|---|---|
1 | Node.js | 1.316 |
2 | なでしこ3 | 4.078 |
3 | PHP8 | 9.695 |
4 | Ruby2.6 | 13.078 |
5 | Python3 | 26.392 |
6 | Perl5 | 36.719 |
(オマケ) 素数計算で対決
次に、オマケで、12345678以下の素数の個数を調べるプログラムで比較してみましょう。
●(最大値の)素数取得とは:
素数リスト=[]
A=真を(最大値+1)だけ配列要素作成。
Iを2から最大値まで繰り返す:
もし、A[I]が真ならば:
素数リストにIを配列追加。
Jを(I*I)から最大値までIずつ増やし繰り返す:
A[J] = 偽
それは素数リスト
12345678の素数取得して要素数を表示。
実行してみましょう。0.785秒です。
time cnako3 soe.nako3
809227
cnako3 soe.nako3 0.73s user 0.08s system 103% cpu 0.785 total
次にPython3です。
def sieve_of_eratosthenes(limit):
primes = []
a = [True] * (limit + 1)
for i in range(2, limit + 1):
if a[i]:
primes.append(i)
for j in range(i*i, limit + 1, i):
a[j] = False
return primes
print(len(sieve_of_eratosthenes(12345678)))
実行してみましょう。1.849秒でした。なでしこよりも2.4倍遅いという結果になりました。
time python3 soe.py
809227
python3 soe.py 1.73s user 0.04s system 96% cpu 1.849 total
続いて、PHPで試してみましょう。
<?php
function sieve_of_eratosthenes($limit) {
$primes = array();
$a = array_fill(0, $limit + 1, true);
for ($i = 2; $i <= $limit; $i++) {
if ($a[$i]) {
array_push($primes, $i);
for ($j = $i * $i; $j <= $limit; $j += $i) {
$a[$j] = false;
}
}
}
return $primes;
}
$primes = sieve_of_eratosthenes(12345678);
echo count($primes)."\n";
PHPで試してみると、メモリエラーで実行できないようになっていました。コマンドラインで-d memory_limit=-1にすると、このエラーを回避できるとのこと、学びになりました。実行時間は、1.775秒でした。
time php -d memory_limit=-1 soe.php
809227
php -d memory_limit=-1 soe.php 1.69s user 0.05s system 98% cpu 1.775 total
素数計算勝負の結果
次のようになりました。今回は、3言語のみの比較ですが、やはり、Python3が遅いという結果です。
| 順位 | 言語 | 処理時間 |
| 1 | なでしこ3 | 0.785 |
| 2 | PHP8 | 1.775 |
| 3 | Python3 | 1.849 |
まとめ
楽しいスクリプト言語ごとの速度結果勝負ですが、どうだったでしょうか。
スクリプト言語では、ChromeのJS実行エンジンを利用しているNode.jsがダントツで速く、虎の威を借る狐である「なでしこ3」は、それに次いで速いという結果になりました。Node.jsと比べると何倍も遅くなっていますが、PHPやPythonよりも速いので十分満足です。
もちろん、言語ごとに、最適化オプションがあるので、もっと速く実行することもできるでしょう。なでしこ3も、素のJavaScriptを出力するモードがあるので、これを利用すると、もっと速く実行できます。また、変数の引数チェックを省略するモードもあるので、それを使うともっと速くなります。
それでも、一番使い勝手の良いデフォルトモードで比較するのが公平なので、できるだけデフォルト状態で試してみました。
皆様の参考になれば幸いです。