Ruby中数组splat操作为何性能开销如此之大?
Ruby中Splat数组构建的性能疑问
我偏好Splat构建数组/哈希的原因
- 它们属于数组、哈希字面量,无需追踪计算流程就能明确最终结果,语法直观清晰
- 便于在单个表达式中构建复杂值,无需采用命令式写法(尽管可以用tap实现单赋值,但可读性差很多)
Splat的性能开销问题
实际测试发现splat操作存在明显性能开销,以下是测试代码和结果:
基础性能测试代码
require 'benchmark' $array = (0...100).to_a n = 100_000 Benchmark.bm do |x| x.report('add ') {n.times{$array + $array + $array}} x.report('splat ') {n.times{[*$array, *$array, *$array]}} end
测试结果
机器A(MRI 3.1.3)
user system total real add 0.031583 0.001421 0.033004 ( 0.033006) splat 0.050174 0.001397 0.051571 ( 0.051584)
机器B(MRI 2.7.4)
user system total real add 0.278377 0.000000 0.278377 ( 0.278316) splat 0.780735 0.043730 0.824465 ( 0.824377)
核心疑问
为什么基于splat的数组构建会这么慢?我原本预期splat不会比普通加法慢——毕竟AST甚至可以将两者转换,甚至应该更高效:语言能掌握所有信息,可避免加法产生的中间数组,还能预先估算最终数组大小并预留空间。
那为什么依赖方法调用(理论上更难被解释器优化)的加法方式,反而比完全暴露给解释器的splat操作更快?
补充测试:多种数组构建方式的性能对比
测试代码
require 'benchmark/ips' ary = (0...100).to_a Benchmark.ips do |x| x.report('add') {ary + ary + ary} x.report('append') {res = ary.dup; res.append(*ary); res.append(*ary); res} x.report('concat2') {res = []; res.concat(ary); res.concat(ary); res.concat(ary); res} x.report('concat3') {[].concat(ary, ary, ary)} x.report('concat_splat') {[].concat(*[ary, ary, ary])} x.report('flatten') {[ary, ary, ary].flatten} x.report('flatten(1)') {[ary, ary, ary].flatten(1)} x.report('splat') {[*ary, *ary, *ary]} x.compare! end
测试结果(机器A,MRI 3.1.3)
Warming up -------------------------------------- add 300.630k i/100ms append 140.913k i/100ms concat2 154.698k i/100ms concat3 120.459k i/100ms concat_splat 142.808k i/100ms flatten 10.329k i/100ms flatten(1) 52.207k i/100ms splat 195.946k i/100ms Calculating ------------------------------------- add 3.040M (± 0.7%) i/s - 15.332M in 5.043760s append 1.400M (± 1.9%) i/s - 7.046M in 5.034067s concat2 1.532M (± 2.1%) i/s - 7.735M in 5.049821s concat3 1.134M (± 2.6%) i/s - 5.782M in 5.101784s concat_splat 1.409M (± 1.9%) i/s - 7.140M in 5.068373s flatten 102.948k (± 0.6%) i/s - 516.450k in 5.016786s flatten(1) 517.582k (± 5.2%) i/s - 2.610M in 5.058161s splat 1.939M (± 1.4%) i/s - 9.797M in 5.052514s Comparison: add: 3039958.8 i/s splat: 1939484.0 i/s - 1.57x (± 0.00) slower concat2: 1532384.2 i/s - 1.98x (± 0.00) slower concat_splat: 1409339.8 i/s - 2.16x (± 0.00) slower append: 1400120.7 i/s - 2.17x (± 0.00) slower concat3: 1134080.2 i/s - 2.68x (± 0.00) slower flatten(1): 517582.1 i/s - 5.87x (± 0.00) slower flatten: 102948.3 i/s - 29.53x (± 0.00) slower
内容的提问来源于stack exchange,提问作者akim
相关产品推荐
相关产品推荐

