[ruby-dev:48942] Boost creating big array from Range#map
From:
SASADA Koichi <ko1@...>
Date:
2015-04-15 20:19:36 UTC
List:
ruby-dev #48942
小ネタ(没ネタ)です。
単に配列を作るのに比べて、大きな Range の map が遅かったので、ちょっと考
えてみたんですが、空配列から push するのが遅いのかな、と思ったので、size
がわかる場合には、最初に空の配列を作るとき、capa をそのサイズにすると、
ちょっとはマシになるかと思いまして。
やってみると、
bench1
user system total real
Array.new(1000000) 0.050000 0.000000 0.050000 ( 0.045718)
Array.new(10000000) 0.440000 0.000000 0.440000 ( 0.450678)
Array.new(100000000) 4.520000 0.080000 4.600000 ( 4.609407)
(1..1000000).map 0.060000 0.000000 0.060000 ( 0.061653)
(1..10000000).map 0.590000 0.010000 0.600000 ( 0.944142)
(1..100000000).map 6.020000 0.180000 6.200000 ( 6.873744)
が、
(1..1000000).map 0.060000 0.010000 0.070000 ( 0.058909)
(1..10000000).map 0.880000 0.020000 0.900000 ( 0.898898)
(1..100000000).map 5.790000 0.050000 5.840000 ( 5.850037)
こうなりました。大きいときに、若干速くなってるかな、という程度ですが...。
小さい enum について、map をすると、逆に遅くなってしまいました。
bench2
user system total real
Array.new(1) 2.530000 0.000000 2.530000 ( 2.532221)
(1..1).map (before) 2.140000 0.000000 2.140000 ( 2.143456)
(1..1).map (after) 2.930000 0.000000 2.930000 ( 2.926502)
というわけで、無しですね。Range#size を毎回まともに呼び出しているから
だろうなあ。Range#size を、わざわざ最適化するのも何だし。
Index: enum.c
===================================================================
--- enum.c (revision 50322)
+++ enum.c (working copy)
@@ -443,10 +443,17 @@
enum_collect(VALUE obj)
{
VALUE ary;
+ VALUE size = enum_size(obj, Qnil, Qnil);
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
- ary = rb_ary_new();
+ if (FIXNUM_P(size)) {
+ ary = rb_ary_new_capa(FIX2INT(size));
+ }
+ else {
+ ary = rb_ary_new();
+ }
+
rb_block_call(obj, id_each, 0, 0, collect_i, ary);
return ary;
# bench1
require 'benchmark'
i = 0
s = 6
e = 8
Benchmark.bm(20){|x|
(s..e).each{|n|
x.report("Array.new(#{10 ** n})"){
Array.new(10 ** n){|x|
true
}
}
}
(s..e).each{|n|
x.report("(1..#{10**n}).map"){
m = (1..(10**n)).map{
true
}
}
}
}
# bench2
require 'benchmark'
n = 10_000_000
Benchmark.bm(20){|x|
x.report("Array.new(1)"){
n.times{
Array.new(1){|x|
true
}
}
}
x.report("(1..1).map"){
n.times{
m = (1..1).map{
true
}
}
}
}
--
// SASADA Koichi at atdot dot net