Ruby:提高效率

时间:2016-06-17 16:23:33

标签: ruby-on-rails arrays ruby optimization benchmarking

我正在处理大量数据,并且我担心我的大规模运营效率。基准测试后,执行此代码串的平均时间约为0.004秒。这行代码的目标是找到每个数组位置中两个值之间的差异。在先前的操作中,111.111被加载到包含无效数据的位置的数组中。由于一些奇怪的时域问题,我需要这样做,因为我不能删除值,我需要一些可区分的占位符。我可以使用' nil'在这里。无论如何,回到解释。这行代码检查以确保这两个数组在当前位置都没有此111.111占位符。如果值有效,那么我执行数学运算,否则我想删除这些值(或者至少将它们从我写入的新数组中排除)。我通过放置一个' nil'在那个位置,然后压缩阵列。

每个阵列中4000个数据点的0.004秒时间并不可怕,但这行代码执行了25M次。我希望有人能够提供一些有关我如何优化这一行代码的见解。

temp_row = row_1.zip(row_2).map do |x, y| 
  x == 111.111 || y == 111.111 ? nil : (x - y).abs 
end.compact

2 个答案:

答案 0 :(得分:2)

您在三元语句中浪费CPU生成nil,然后使用compact删除它们。相反,请使用rejectselect查找不包含111.111然后map或类似内容的元素。

而不是:

row_1 = [1, 111.111, 2]
row_2 = [2, 111.111, 4]

temp_row = row_1.zip(row_2).map do |x, y| 
  x == 111.111 || y == 111.111 ? nil : (x - y).abs 
end.compact
temp_row # => [1, 2]

我从:

开始
temp_row = row_1.zip(row_2)
                .reject{ |x,y| x == 111.111 || y == 111.111 }
                .map{ |x,y| (x - y).abs }
temp_row # => [1, 2]

或者:

temp_row = row_1.zip(row_2)
                .each_with_object([]) { |(x,y), ary|
                  ary << (x - y).abs unless (x == 111.111 || y == 111.111)
                }
temp_row # => [1, 2]

对不同大小的数组进行基准测试显示了很多好处:

require 'benchmark'

DECIMAL_SHIFT = 100
DATA_ARRAY = (1 .. 1000).to_a
ROW_1 = (DATA_ARRAY + [111.111]).shuffle
ROW_2 = (DATA_ARRAY.map{ |i| i * 2 } + [111.111]).shuffle

Benchmark.bm(16) do |b|
  b.report('ternary:') do
    DECIMAL_SHIFT.times do
      ROW_1.zip(ROW_2).map do |x, y| 
        x == 111.111 || y == 111.111 ? nil : (x - y).abs 
      end.compact
    end
  end

  b.report('reject:') do
    DECIMAL_SHIFT.times do
      ROW_1.zip(ROW_2).reject{ |x,y| x == 111.111 || y == 111.111 }.map{ |x,y| (x - y).abs }
    end
  end

  b.report('each_with_index:') do
    DECIMAL_SHIFT.times do
      ROW_1.zip(ROW_2)
           .each_with_object([]) { |(x,y), ary|
             ary += [(x - y).abs] unless (x == 111.111 || y == 111.111)
           }
    end
  end
end

# >>                        user     system      total        real
# >> ternary:           0.240000   0.000000   0.240000 (  0.244476)
# >> reject:            0.060000   0.000000   0.060000 (  0.058842)
# >> each_with_index:   0.350000   0.000000   0.350000 (  0.349363)

调整DECIMAL_SHIFTDATA_ARRAY的大小以及111.111的位置,看看会发生什么情况,以了解哪些表达式最适合您的数据大小和结构以及微调必要的代码。

答案 1 :(得分:0)

您可以尝试parallel gem https://github.com/grosser/parallel并在多个线程上运行