====== ベンチマークその1(フィボナッチ数列の計算) ====== ちょっと意見いただいたのもあり、ベンチマークを適当に書いてみることにしました。 ==== 諸注意 ==== 今回の結果は管理人の環境における結果で、他の環境やOSだと変わる要因があるかもしれません。 よって、参考程度とお考えください。 ==== 管理人のPC環境 ==== * CPU:Intel Core i5-6400 * メモリ:16GB ==== 候補 ==== * Lua5.4.4 * Python3.9.8 * Ruby3.2.9 * Squirrel3.1stable * Miniscript1.5.1 ==== 内容 ==== フィボナッチ数列の計算速度(開始から終了までにかかった時間)を取得する。 VMを実行するため仮想バイトコードに変換するだろうと考え、中でタイマ処理を追加してます。 ==== 結果 ==== Lua:4.444sec Python:12.4836sec Ruby:4.95057sec Squirrel:13sec(ms単位で計測できない) Miniscript:計測不能(結果が帰ってこない) 速度: Lua > Ruby > Python >= Squirrel(Pythonとの差は微量かも) >>>>>>>>>>>> Miniscript ==== 感想 ==== 遅いよMiniscript!(涙 ただ上記の通り環境によっても変わると思いますし、数値の取り扱いが小数を含む形に固定されてる、変数やリスト・マップの取り扱いがかなり自由である等、仕様上数値計算に特化している言語と比較するとやりづらいところがあるかもしれません。 あと、コミュニティの厚みの差がモロに性能に反映されてる気がしないでもない・・・ (コマンドライン版Miniscriptは2019年初出) === 20230122追記 === コミュニティでこんな意見あり。 > MiniScript's call overhead is quite high; recursive Fibonacci is pretty much a worst-case for it. > That's why it's one of the benchmarks in the benchmark suite. まずMiniscript自体のオーバーヘッドが非常に高くて、今回の実装におけるフィボナッチ数列はそのオーバーヘッド高い状態でぶん回すわけだから、そりゃ負荷がべらぼうに高いわなと。(ワーストケースって言ってるし) 簡単な対策としては、フィボナッチ数列を組込関数にするか、基本的には再帰呼び出しを避けて書き下すアプローチが一番効率よさそう。 ---- そもそもベンチマークに使ったアルゴリズムは無茶苦茶な量の計算になるので、現実問題としてスクリプト側でやらせるようなやつではないとも考えます。 (どういう使い方が最適なのか、方針を立てるというのもベンチマークの目的であると考えますし) 日常的なバッチレベルのものだったり他のソフトに投げる程度であれば使うのは有効だけど、Miniscript単体で大量に計算するものだと避けるのは無難って感じだと思います。 ただ、その計算もフィボナッチ数列に匹敵するレベルでなければ問題ないのはわかったので、言語使う際の方針を立てやすくなったと考えます。 基本方針は以下の通りかと。 * 書き下しレベルの内容や計算量の多くないものであればMiniscriptで行う * 再帰呼び出し等による大量の計算がスクリプト側で発生する場合、ベース言語側にオフロードできるか検討する 管理人のゲーム開発で使う際は以下の基準で利用しています。 * 基本的にはフィボナッチ数列のようにスクリプト上で大量に計算させる処理は避ける(組込関数で実装する等) * スクリプトを読むオブジェクトのしきい値は50個を基準にする(うちの環境だとEditor上で問題なく動く基準。本来ならもっと動かせると思うしGPU周りの要因もあるけど。) * 大量のオブジェクトを動かす場合(1000個程度)ベース言語側で対応する 実際キャラクターの行動プログラムについてはかなり複雑に書いてますし、多関節アニメとかもプログラムで書いてますが、処理に不足はありません。 === 対策 === とは言うものの、上記の計算の時間をなんとか改善する方法はあるんでしょうか?一応あるんです。 言ってしまうとアルゴリズムの改善ですね。 https://rosettacode.org/wiki/Fibonacci_sequence#MiniScript 以前に自分も書きましたが同様の方法ですね。 https://machiaworx.net/?p=648 こんな感じでアルゴリズム上でなんとかしていく正統派なアプローチが必要になってきます。 (ちなみにこの方法だと1秒もかからずに処理が出力されます) ==== 当記事の結論 ==== 管理人の環境では、Miniscriptは再帰的な数値計算のベンチマークはとっても遅い。 ただ、アルゴリズムの改造で遅さをカバー可能。 (おそらく実装された記法やリスト・マップの柔軟さに重きを置いてるのかなあと思ったりする。Pythonに近い方向性というか) ===== ソースコード ===== ==== 参考資料 ==== http://www.furelo.jp/wordpress/?p=62 https://ma-tech.centurysys.jp/doku.php?id=mae3xx_tips:test_fib_benchmark:start https://qiita.com/yakiimo23/items/7293c7606c1d59501d89 https://imagingsolution.net/program/python/python-basic/processing_time/ ==== Lua ==== function fib(n) if n < 2 then return n end return fib(n - 2) + fib(n - 1) end x = os.clock() print(fib(38)) print (os.clock() - x) ==== python ==== import time def fib(n): if n < 2: return n return fib(n - 2) + fib(n - 1) start = time.perf_counter() print(fib(38)) print(time.perf_counter() - start) ==== Ruby ==== require 'benchmark' def fib(n) return n if (n < 2) return fib(n - 2) + fib(n - 1) end result = Benchmark.realtime do puts fib(38) end puts "sec #{result}s" ==== Squirrel ==== function fib(n) { if (n < 2) return n; else return fib(n - 2) + fib(n - 1); } local a=time() print(fib(38).tostring() + "\n"); print(time()-a) ==== Miniscript ==== fib=function(n=0) if n<2 then return n end if x =fib(n-2) + fib(n-1) return x end function tm=time() print fib(38) print time()-tm