色々な言語でたらい回し関数の速度を比較してみたという, 色々なたらい回し関数を実装して速度比較をしている記事を読んだ。
他の言語と比較してメモリ使用量は大きいけれども,Julia言語はそこそこのスピートが出ていた。
個人的にJulia言語は再帰関数が苦手と思っていたのでこの結果は少し意外だった。
とは言うものの簡単な方法でさらにドーピングできないかとネットでぐぐってみた。
すると,末尾再帰最適化マクロを作ってみたという記事が見つかり, TailRec.jlというモジュールを使うと手軽に再帰関数を高速化できそうということが分かった。
次のようにパッケージモードに入ってモジュールを追加する。
(@v1.10) pkg> add https://github.com/TakekazuKATO/Tailrec.jl Cloning git-repo `https://github.com/TakekazuKATO/Tailrec.jl` Updating git-repo `https://github.com/TakekazuKATO/Tailrec.jl` Updating registry at `~/.julia/registries/General.toml` Resolving package versions... Updating `~/.julia/environments/v1.10/Project.toml` [f6209947] + TailRec v0.2.0 `https://github.com/TakekazuKATO/Tailrec.jl#master` Updating `~/.julia/environments/v1.10/Manifest.toml` [f6209947] + TailRec v0.2.0 `https://github.com/TakekazuKATO/Tailrec.jl#master` Precompiling project... 1 dependency successfully precompiled in 3 seconds. 463 already precompiled.
そして,次のようにソースを修正。
# tarai2-tailrec.jl using TailRec @tailrec function tarai(x, y, z) if x <= y y else tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y)) end end println(tarai(15, 5, 0))
次が結果の比較。
ujimushi@ubuntu-24.04:~/blog/test$ \time -o /dev/stdout -f real:%e[sec]_user:%U[sec]_sys:%S[sec]_Memory:%M[KB] julia -O3 tarai2.jl 15 real:6.00[sec]_user:5.90[sec]_sys:0.61[sec]_Memory:316416[KB] ujimushi@ubuntu-24.04:~/blog/test$ \time -o /dev/stdout -f real:%e[sec]_user:%U[sec]_sys:%S[sec]_Memory:%M[KB] julia -O3 tarai2-tailrec.jl 15 real:5.00[sec]_user:4.91[sec]_sys:0.61[sec]_Memory:316492[KB]
最適化をレベル3にすると,およそ1秒の高速化となった。なお,println(tarai(16, 5, 0))に変更すると,
実行時間は約37秒と約29秒だったので,処理の短縮時間はおよそ処理時間に比例するということが分かった。
高速になる仕組みは末尾再帰最適化マクロを作ってみたに詳しいので (私がよく分からないからともいう)そちらを見ていただきたいのだが,多分再帰関数で終端までいったら大元の呼び出し元まで ジャンプで一気に戻る,というのをマクロで実現しているということだと想像する。
このように,Julia言語では便利なパッケージを知っているだけで高速化が実現できたりもする。
この例の面白いのはPythonで多いようにC言語等他の言語モジュールを利用して高速化するというのではなく, Julia言語の機能のみを利用して高速化しているところ。
おそらく,記事で使っているRaspberry Pi 5だと9~10秒→7~8秒ぐらいに変わるという程度の結果なので,
プログラミング言語間の計算速度分布の大勢には影響がない程度だと思う。