sno*_*ard 21 ruby arrays performance
我对Ruby的数组concat()
与+
操作进行了小的性能测试,但concat()
速度太快了.
但是我不明白为什么concat()
这么快?
有人可以帮忙吗?
这是我使用的代码:
t = Time.now
ar = []
for i in 1..10000
ar = ar + [4,5]
end
puts "Time for + " + (Time.now - t).to_s
t = Time.now
ar = []
for i in 1..10000
ar.concat([4,5])
end
puts "Time for concat " + (Time.now - t).to_s
Run Code Online (Sandbox Code Playgroud)
Chr*_*ell 14
答案在于Ruby的+
运算符和concat
方法的底层C实现.
rb_ary_plus(VALUE x, VALUE y)
{
VALUE z;
long len, xlen, ylen;
y = to_ary(y);
xlen = RARRAY_LEN(x);
ylen = RARRAY_LEN(y);
len = xlen + ylen;
z = rb_ary_new2(len);
ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x));
ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y));
ARY_SET_LEN(z, len);
return z;
}
Run Code Online (Sandbox Code Playgroud)
rb_ary_concat(VALUE x, VALUE y)
{
rb_ary_modify_check(x);
y = to_ary(y);
if (RARRAY_LEN(y) > 0) {
rb_ary_splice(x, RARRAY_LEN(x), 0, y);
}
return x;
}
Run Code Online (Sandbox Code Playgroud)
如您所见,+
操作员正在从每个阵列复制内存,然后创建并返回包含两者内容的第三个数组.该concat
方法只是将新阵列拼接成原始阵列.
如果您要运行基准测试,请利用预构建工具并将测试降低到测试您想要知道的最低要求.
从Fruity开始,它为其基准测试提供了大量智能:
require 'fruity'
compare do
plus { [] + [4, 5] }
concat { [].concat([4, 5]) }
end
# >> Running each test 32768 times. Test will take about 1 second.
# >> plus is similar to concat
Run Code Online (Sandbox Code Playgroud)
当事情足够接近而不是真的担心时,Fruity会告诉我们他们"相似".
那时Ruby的内置Benchmark类可以帮助:
require 'benchmark'
N = 10_000_000
3.times do
Benchmark.bm do |b|
b.report('plus') { N.times { [] + [4, 5] }}
b.report('concat') { N.times { [].concat([4,5]) }}
end
end
# >> user system total real
# >> plus 1.610000 0.000000 1.610000 ( 1.604636)
# >> concat 1.660000 0.000000 1.660000 ( 1.668227)
# >> user system total real
# >> plus 1.600000 0.000000 1.600000 ( 1.598551)
# >> concat 1.690000 0.000000 1.690000 ( 1.682336)
# >> user system total real
# >> plus 1.590000 0.000000 1.590000 ( 1.593757)
# >> concat 1.680000 0.000000 1.680000 ( 1.684128)
Run Code Online (Sandbox Code Playgroud)
注意不同的时间.运行一次测试可能会导致误导结果,因此请多次运行它们.此外,请确保您的循环导致的时间不会被过程启动引起的背景噪音所掩盖.