gpt4 book ai didi

arrays - Ruby 中哪个更快, `arr += [x]` 或 `arr << x`

转载 作者:数据小太阳 更新时间:2023-10-29 06:44:22 26 4
gpt4 key购买 nike

直觉上,后者应该比前者快。然而,当我看到基准测试结果时,我感到非常惊讶:

  require 'benchmark/ips'

b = (0..20).to_a;
y = 21;
Benchmark.ips do |x|
x.report('<<') { a = b.dup; a << y }
x.report('+=') { a = b.dup; a += [y] }
x.report('push') { a = b.dup; a.push(y) }
x.report('[]=') { a = b.dup; a[a.size]=y }
x.compare!
end

结果是:

Calculating -------------------------------------
<< 24.978k i/100ms
+= 30.389k i/100ms
push 24.858k i/100ms
[]= 22.306k i/100ms
-------------------------------------------------
<< 493.125k (± 3.2%) i/s - 2.473M
+= 599.830k (± 2.3%) i/s - 3.009M
push 476.374k (± 3.3%) i/s - 2.386M
[]= 470.263k (± 3.8%) i/s - 2.364M

Comparison:
+=: 599830.3 i/s
<<: 493125.2 i/s - 1.22x slower
push: 476374.0 i/s - 1.26x slower
[]=: 470262.8 i/s - 1.28x slower

然而,当我的一位同事独立创建了自己的基准时,结果却恰恰相反:

 Benchmark.ips do |x|
x.report('push') {@a = (0..20).to_a; @a.push(21)}
x.report('<<') {@b = (0..20).to_a; @b << 21}
x.report('+=') {@c = (0..20).to_a; @c += [21]}
x.compare!
end

结果:

Calculating -------------------------------------
push 17.623k i/100ms
<< 18.926k i/100ms
+= 16.079k i/100ms
-------------------------------------------------
push 281.476k (± 4.2%) i/s - 1.410M
<< 288.341k (± 3.6%) i/s - 1.457M
+= 219.774k (± 8.3%) i/s - 1.093M

Comparison:
<<: 288341.4 i/s
push: 281476.3 i/s - 1.02x slower
+=: 219774.1 i/s - 1.31x slower

我们还交叉运行了我们的基准测试,在我们的两台机器上,他的基准测试显示 +=明显慢于 << ,而我的则相反。

这是为什么?

UPD:我的 Ruby 版本是 Ruby 2.2.3p173(2015-08-18 修订版 51636)[x86_64-darwin14];我同事的是 2.2.2(不知道完整的细节,明天会更新帖子)。

UPD2:ruby 2.2.2p95(2015-04-13 修订版 50295)[x86_64-darwin12.0] 我队友的 Ruby 版本。

最佳答案

在我看来,为了简化各种运算符的比较,我们应该删除不必要的代码并保持测试简单。

require 'benchmark/ips'

y = 10
Benchmark.ips do |x|
x.report('<<') { a = [0,1,2,3,4,5,6,7,8,9]; a << y }
x.report('+=') { a = [0,1,2,3,4,5,6,7,8,9]; a += [y] }
x.report('push') { a = [0,1,2,3,4,5,6,7,8,9]; a.push(y) }
x.report('[]=') { a = [0,1,2,3,4,5,6,7,8,9]; a[a.size]=y }
x.compare!
end

上述代码的结果与问题中共享的第二个代码片段一致。

Calculating -------------------------------------
<< 101.735k i/100ms
+= 104.804k i/100ms
push 92.863k i/100ms
[]= 99.604k i/100ms
-------------------------------------------------
<< 2.134M (± 3.3%) i/s - 10.682M
+= 1.786M (±13.2%) i/s - 8.804M
push 1.930M (±16.1%) i/s - 9.472M
[]= 1.948M (± 7.9%) i/s - 9.761M

Comparison:
<<: 2134005.4 i/s
[]=: 1948256.8 i/s - 1.10x slower
push: 1930165.3 i/s - 1.11x slower
+=: 1785808.5 i/s - 1.19x slower

[Finished in 28.3s]

为什么 <<+= 快?

Array#<< 是四种将元素附加到数组的方法中最快的,因为它就是这样做的——将一个元素附加到数组。相反, Array#+ 追加一个元素但返回数组的新副本 - 创建数组的新副本使其最慢。 (可以使用文档中的 toogle code 选项来了解某些方法完成的额外工作)

基准标记 dup

如果我们使用下面的代码进行基准测试,

require 'benchmark/ips'

y = 10
Benchmark.ips do |x|
x.report('<<') { a = [0,1,2,3,4,5,6,7,8,9].dup; a << y }
x.report('+=') { a = [0,1,2,3,4,5,6,7,8,9].dup; a += [y] }
x.report('push') { a = [0,1,2,3,4,5,6,7,8,9].dup; a.push(y) }
x.report('[]=') { a = [0,1,2,3,4,5,6,7,8,9].dup; a[a.size]=y }
x.compare!
end

我们看到以下结果:

Calculating -------------------------------------
<< 65.225k i/100ms
+= 76.106k i/100ms
push 64.864k i/100ms
[]= 63.582k i/100ms
-------------------------------------------------
<< 1.221M (±14.3%) i/s - 6.001M
+= 1.291M (±13.1%) i/s - 6.393M
push 1.164M (±14.1%) i/s - 5.773M
[]= 1.168M (±14.5%) i/s - 5.722M

Comparison:
+=: 1290970.6 i/s
<<: 1221029.0 i/s - 1.06x slower
[]=: 1168219.3 i/s - 1.11x slower
push: 1163965.9 i/s - 1.11x slower

[Finished in 28.3s]

如果我们仔细观察两个结果,我们只会发现一个差异。 += entry 变为第一个,而其余方法的顺序与原始结果相同。

为什么当 dup 时结果翻转是用的吗?

这是我的大胆猜测,我猜测 Ruby 解释器优化了代码并且没有创建新数组作为 += 的一部分|因为它知道它正在处理新创建的数组副本 dup

关于arrays - Ruby 中哪个更快, `arr += [x]` 或 `arr << x`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34207459/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com