#inject и медлительность

Я часто слышал, как метод инъекции Руби критиковали как «медленный». Поскольку мне больше нравится эта функция, и я вижу эквиваленты на других языках, мне любопытно, является ли это просто Ruby выполнение медленного метода или это по своей сути медленный способ делать что-то (например, его следует избегать для немалых коллекций )?

Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
1
0
646
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

inject похож на fold и может быть очень эффективным на других языках, в частности на fold_left, поскольку он хвостовой рекурсивной.

В основном это проблема реализации, но это дает вам хорошее представление о сравнении:

$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
$ ruby exp/each_v_inject.rb 
Rehearsal -----------------------------------------------------
loop                0.000000   0.000000   0.000000 (  0.000178)
fixnums each        0.790000   0.280000   1.070000 (  1.078589)
fixnums each add    1.010000   0.290000   1.300000 (  1.297733)
Enumerable#inject   1.900000   0.430000   2.330000 (  2.330083)
-------------------------------------------- total: 4.700000sec

                        user     system      total        real
loop                0.000000   0.000000   0.000000 (  0.000178)
fixnums each        0.760000   0.300000   1.060000 (  1.079252)
fixnums each add    1.030000   0.280000   1.310000 (  1.305888)
Enumerable#inject   1.850000   0.490000   2.340000 (  2.340341)

exp / each_v_inject.rb

require 'benchmark'

total = (ENV['TOTAL'] || 1_000).to_i
fixnums = Array.new(total) {|x| x}

Benchmark.bmbm do |x|
  x.report("loop") do
    total.times { }
  end

  x.report("fixnums each") do
    total.times do |i|
      fixnums.each {|x| x}
    end
  end

  x.report("fixnums each add") do
    total.times do |i|
      v = 0
      fixnums.each {|x| v += x}
    end
  end    

  x.report("Enumerable#inject") do
    total.times do |i|
      fixnums.inject(0) {|a,x| a + x }
    end
  end  
end

Так что да, это медленно, но по мере улучшения реализации этого не должно быть проблемой. В том, ЧТО он делает, нет ничего такого, что требовало бы того, чтобы оно было медленнее.

each_with_object может быть быстрее, чем inject, если вы изменяете существующий объект, а не создаете новый объект в каждом блоке.

Другие вопросы по теме