ruby - Why is `inject` very slow? -
here benchmark
require 'benchmark' # create random array arr = 40000.times.map { rand(100000).to_s } r1 = '' r2 = '' r3 = '' benchmark.bm |x| x.report { r1 = (arr.map { |s| "[#{s}]" }).join } x.report { r2 = arr.inject('') { |memo, s| memo + "[#{s}]" } } x.report { r3 = '' arr.each { |s| r3 << "[#{s}]" } } end # confirm result same puts r1 == r2 puts r2 == r3
here result
user system total real 0.047000 0.000000 0.047000 ( 0.046875) 5.031000 0.844000 5.875000 ( 5.875000) 0.031000 0.000000 0.031000 ( 0.031250) true true
has way make inject
faster ?
here's guess: unlike 2 other methods, approach inject
keeps creating bigger , bigger strings. of them (except last) temporary , have garbage-collected. that's wasted memory , cpu right there. example of shlemiel painter's algorithm.
... inefficiency spolsky drawing analogy poor programming practice of repeated concatenation of c-style null-terminated character arrays (that is, strings) in position of destination string has recomputed beginning of string each time because not carried on previous concatenation. ...
approach map
creates many small strings, so, @ least, doesn't spend time allocating memory.
update
as pointed out yevgeniy anfilofyev in comments, can avoid creation of many big strings not creating any. keep appending memo
.
r2 = arr.inject('') { |memo, s| memo << "[#{s}]" }
this works because both string#+
, string#<<
return new value string.
Comments
Post a Comment