背景
以前に sample と rand についてベンチマークを比較した記事を書きましたが、いくつか見直すべき点があったため改めて投稿したいと思います。
検証
Kernel.#rand より Random.rand
前記事では Random.rand と言いながら Kernel.#rand(つまり単に rand) を混同して使っていました。
なので改めて以下のように Kernel.#rand と Random.rand を比較してみます。
num = 10000
count = 1000000
Benchmark.bm 20 do |r|
r.report 'Kernel.#rand' do
count.times do
rand(num)
end
end
r.report 'Random.rand' do
count.times do
Random.rand(num)
end
end
end
user system total real
Kernel.#rand 0.190434 0.000193 0.190627 ( 0.190932)
Random.rand 0.084481 0.000194 0.084675 ( 0.084819)
Random.rand のほうが2倍以上高速でした。
range より +1
rand の引数には Range オブジェクトを受け取ることが出来ますが、1以上10000以下のような範囲なら 1..10000 の Range より 10000 の Ingeger を与えて +1 するほうが高速です(rand(10000) は 0〜9999 の値をランダムで返すため)。
Benchmark.bm 20 do |r|
r.report 'Random.rand(range)' do
num.times do
Random.rand(range)
end
end
r.report 'Random.rand(+1)' do
num.times do
Random.rand(10000) + 1
end
end
end
user system total real
Random.rand(range) 0.243092 0.000319 0.243411 ( 0.244819)
Random.rand(+1) 0.084825 0.000072 0.084897 ( 0.085032)
3倍近く早くなってます。
結果
以上を踏まえて Array#sample も加えてベンチマークを取ってみます。
num = 10000
range = (1..num)
array = range.to_a
count = 1000000
Benchmark.bm 20 do |r|
r.report 'Array#sample' do
count.times do
array.sample
end
end
r.report 'Kernel.#rand(range)' do
count.times do
rand(range)
end
end
r.report 'Kernel.#rand(+1)' do
count.times do
rand(num) + 1
end
end
r.report 'Random.rand(range)' do
count.times do
Random.rand(range)
end
end
r.report 'Random.rand(+1)' do
count.times do
Random.rand(num) + 1
end
end
end
user system total real
Array#sample 0.143643 0.000186 0.143829 ( 0.144033)
Kernel.#rand(range) 0.137866 0.000146 0.138012 ( 0.138163)
Kernel.#rand(+1) 0.194007 0.000154 0.194161 ( 0.194374)
Random.rand(range) 0.244600 0.000151 0.244751 ( 0.244960)
Random.rand(+1) 0.086753 0.000071 0.086824 ( 0.086926)
結果的には Random.rand に +1 するのが予想通り最速でしたが、Array#sample もそこまで遅いわけではないようです。
また、Range オブジェクトを渡す場合は Random.rand より Kernel.#rand のほうが速いというのは意外でした。もし1始まり以外の範囲を使いたい場合は Kernel.#rand を使っても良さそうです。それと range.to_a はループの度にやると非常に遅いので事前に用意しておくのが重要です。
最後に
ランチェスターではパフォーマンスにうるさいサーバーサイドエンジニア社員を募集しております!
まずはざっくばらんにお話しさせてください。下記からご応募お待ちしております。
▼https://herp.careers/v1/lanchester/Bucw0mXRKogc
▼https://www.wantedly.com/companies/lanchester
▼採用動画について:https://moovy.jp/job/651