Ruby'ленивый' менее производительный, чем выделение огромных списков?
Я пытаюсь обработать большой список чисел:
require 'benchmark'
N = 999999
Benchmark.bm 10 do |bm|
bm.report 'Eager:' do
(0..N).select(&:even?).map{|x| x * x}.reduce(&:+)
end
bm.report 'Lazy:' do
(0..N).lazy.select(&:even?).map{|x| x * x}.reduce(&:+)
end
end;
Насколько я понимаю, ленивая версия должна быть намного быстрее, потому что нетерпеливой версии нужно выделить два списка по полмиллиона элементов в каждом (один для select
и один для map
) пока ленивая версия все течет.
Тем не менее, когда я запускаю его, ленивая версия занимает более чем вдвое дольше, чем нетерпеливая! ( http://rextester.com/OTEX7399)
user system total real
Eager: 0.210000 0.010000 0.220000 ( 0.216572)
Lazy: 0.580000 0.000000 0.580000 ( 0.635091)
Как это может быть?
1 ответ
Я бы сказал, что Enumerator намного медленнее среднего уровня, чем память.
Об этом также сообщалось некоторое время назад, и член основной команды Ruby Юсуке Эндо сказал:
Перечислитель:: Ленивый не серебряная пуля; он устраняет накладные расходы на создание промежуточного массива, но имеет недостаток для вызова блока. К сожалению, последний намного больше, чем первый. Таким образом, в общем, Lazy имеет недостаток производительности.
Аналогия, о которой я только что подумал: представьте, что вы создаете мебель для друга.
Не ленивый: Вы строите все это, арендуете грузовик и едете к своему другу.
Ленивый: Вы строите маленький кусочек и едете на машине к другу. Вы строите следующий маленький кусочек и едете на машине к своему другу. Вы строите следующий маленький кусочек и едете на машине к своему другу. И так далее.
Да, аренда этого грузовика - это дополнительные расходы, но это ничто по сравнению с ездой снова и снова с вашим автомобилем.
Настоящая причина, по которой ленивость может сэкономить время, заключается в том, что после первых нескольких пьес ваш друг узнает, что вы переспали с его женой, и теперь вы больше не друзья, и он больше не хочет вашей дурацкой мебели и не строит оставшиеся кусочки вообще.