やわらかテック

興味のあること。業務を通して得られた発見。個人的に試してみたことをアウトプットしています🍵

【Ruby】なぜeach関数よりもfor inが遅いのか

先日、以下の記事を公開しました。

www.okb-shelf.work

Rubyで配列からハッシュを作る際に、どの方法が一番パフォーマンスが良いのかを計測したのですが、過去にJavaScriptで似たような計測をした時はシンプルなfor文が最速だったので、Rubyでも同じような結果になると思っていたらfor inが最も遅く、each関数が最も速いという結果になりました。

一体、なぜこのような結果になるのか。Rubyの深い部分まで把握する必要がありそうだと判断し、前回の記事では調査を行わなかったのですが、今回はその謎に迫ってみたいと思います。

そもそもRubyにはfor文がない

この記事を書く前までRubyには他言語と同様にfor文が定義されているものだと思っていましたが、それが勘違いであることに気づきました。Rubyでは繰り返し処理を記述したい場合、whileやeach関数を使うのが一般的です。例えば、JavaScriptでは10回、文字列を出力する際に以下のように書きます。

for (let i = 0; i < 10; i++) {
  console.log('hello!');
}

よくある一般的なfor文かなと思います。それに対して、Rubyでは一例として以下のように書きます。

for x in 1..10 do
  puts "hello!"
end

前回の計測でeach関数よりも遅いと判明したfor inです。
パッと見た感じ、どちらも同じ一般的な繰り返し処理に見えますが、Rubyのfor inはJavaScriptで実装されているfor文とは似て非なるものです。一体、何が違うのでしょうか。

for inは糖衣構文

なんとRubyのfor inは糖衣構文であり、内部でeach関数に近しい処理を実行しているそうです。

先ほどはRubyの組み込みのループプリミティブはwhileとuntilだけだと言いました。
ではこの「for」というものは何でしょうか。実際には、forはほぼ糖衣構文といえるものです。

Programming Ruby: The Pragmatic Programmer's GuideのFor...inより

つまりfor inを呼び出すと内部ではeach関数に近しい処理に変換されているということが分かりました。

# list.each { |x| puts x } に近しいものに変換される
for x in [1,2,3] do
  puts x
end

なるほど...確かにそれならfor inがeach関数よりも遅いという説明がつきますね。
つまりRubyにはfor文は実装されていないということになります。ただ、ループのプリミティブな定義はwhileuntilだけとありましたが、each関数はどうなのでしょうか。内部でwhileを呼び出していたりするのでしょうか。

array.cを見てみる

いよいよ最深部へ...。RubyのC言語実装のコードへやってきました。
each関数が実装されているのはarray.cというファイルだそうです。

VALUE
rb_ary_each(VALUE ary)
{
    long i;
    ary_verify(ary);
    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    for (i=0; i<RARRAY_LEN(ary); i++) {
        rb_yield(RARRAY_AREF(ary, i));
    }
    return ary;
}

まずeach関数の実装がC言語のファイルにあるということで、each関数が内部でRubyのwhileもしくはuntilを呼び出していないことが分かりました。each関数のパフォーマンスが良いのは内部でC言語のコードを呼び出して実行しているからというのが理由の一つなのでしょうね。

この実装の詳細については分かりかねますが、明らかなのはC言語のfor文を使って、配列の処理を行なっているという点です。

まとめ

  • for inはeach関数と比べるとパフォーマンスで劣る
  • Rubyにはプリミティブなfor文が用意されておらず、whileuntilのみ
  • なんとfor inは糖衣構文であり、内部でeach関数に近しい処理を行なっている
  • each関数はC言語で実装されており、内部ではC言語のfor文が記述されている

少しでも「ええな〜」と思ったらイイネ!・シェア!・はてなブックマークを頂けると励みになります。

参考文献