里々は何故遅いのか

 - by Don

「loop関数は毎回呼び出し先の名前探してるから遅いのでは」的な見解を目にしたので、それなら名前参照せず処理直打ちのtimesなどの関数は早かろう、と思って計測してみました。

実験

*loopテスト
:[開始](現在分):(現在秒)(loop,my_loop,1000000)
[終了](現在分):(現在秒)
@my_loop
【処理】

*timesテスト
:[開始](現在分):(現在秒)(times,1000000,【処理】)
[終了](現在分):(現在秒)

*whileテスト
:[開始](現在分):(現在秒)(while,(C0)< 1000000,【処理】)
[終了](現在分):(現在秒)

*forテスト
:[開始](現在分):(現在秒)(for,1,1000000,【処理】)
[終了](現在分):(現在秒)

【処理】のところは以下の3パターンを試しました。

  • 空白(空回し)
  • (nop,)
  • (set,hoge,)

結果がこちら。1000000ループ処理にかかった秒数。

ループ関数 空回し nop set
loop 0 86 140
times 0 35 87
while 104 138 191
for 0 36 88

考察

whileは空回し中もカウンタのインクリメントや条件式判定を行なっているので時間がかかっています。nopやsetは隣同士の差を見ると純粋な関数自身の処理コストが読み取れるっぽいですね。平均してnopは処理コスト35、setは処理コスト88くらい?

loopは空回しでは名前参照しないようですが処理が存在すれば名前参照のコストも含んでいるようです。大体50程度。

timesやforを使えばループ自体のコストはほぼ0と言えそうです。ただ内部関数の呼び出しにかかるコストそのものがloopで浪費していた名前参照のコストに比べて大きなウェイトを占めている印象を受けます。括弧の展開と内部関数のコールは同じくらいのコストと考えても良いのかもしれません。

それから通常ループでカウンタを使わないということはほぼあり得ないので結局はwhileと同じ程度の処理を自前で行うことになるでしょうし、1回のsetで済む単純なループ処理なども実用上は少ないでしょうから結局は内部関数の呼び出しコストが積もり積もって遅くなる、という結論です。塵も積もれば山となる。

里々は重い処理に向かないという今更なお話でした。

No comments yet.