S
s.ross
# of iterations = 1000000
user system total real
null_time 0.218000 0.000000 0.218000 ( 0.219000)
split/each/<<+ 24.516000 0.140000 24.656000 ( 24.703000)
split/map/<<+ 26.109000 0.172000 26.281000 ( 26.281000)
split/inject/<<+ 30.797000 0.172000 30.969000 ( 31.000000)
Being an FP nut used to using folds, I'm always a little annoyed that
inject fares so poorly in these things; mainly we're just lacking a
C implementation of Array#inject.
coming back to this point... what do you mean by we're missing a C
impl of Array#inject? Granted, the impl is on Enumerable, but I
wouldn't think it would make THAT much of a difference... But I try
my best not to speculate (ever), so...
(my C coding skills absolutely suck these days, please point out
improvements)
#!/usr/bin/env ruby -w
require 'benchmark'
require 'ipaddr'
$: << File.expand_path("~/Work/p4/zss/src/RubyInline/dev/lib")
require 'inline'
class Array
inline do |builder|
builder.c_raw <<-EOF
VALUE new_inject(int argc, VALUE *argv, VALUE self) {
long max = RARRAY(self)->len;
long i = argc ? 0 : 1;
VALUE memo = argc ? argv[0] : RARRAY(self)->ptr[0];
for (i; i < max; i++) {
memo = rb_yield_values(2, memo, RARRAY(self)->ptr);
}
return memo;
}
EOF
end
end
p "127.0.0.1".split('.').inject(0) { |s,n| (s << 8) + n.to_i }
p "127.0.0.1".split('.').new_inject(0) { |s,n| (s << 8) + n.to_i }
max = (ARGV.shift || 1_000_000).to_i
# # of iterations = 1000000
# user system total real
# null_time 0.130000 0.000000 0.130000 ( 0.129965)
# split/each/<< 10.940000 0.010000 10.950000 ( 10.968329)
# split/inject/<< 15.280000 0.020000 15.300000 ( 15.330062)
# split/new_inject/<< 15.020000 0.070000 15.090000 ( 15.629343)
The question I would ask is not why does inject suck, but why doesn't
each suck? There is only so much you can optimize in C, and you've
really only optimized the loop -- not the arithmetic operation because
that is yielded back to Ruby.