Ruby Code Performance Tweaks
- 2010-05-04
- Kurt Stephens – kurt@enovafinancial.com
- Enova Financial
- http://kurtstephens.com/pub/ruby/ruby_code_tweaks/
- http://github.com/kstephens/ruby_code_tweaks/
Start a ruby process N times.
n.times do
# SOLUTION?
end
system("ruby ...")
system("ruby ...")
n.times do
system("#{$platform_cmd_line} -e 'exit 0'") or
raise "failed"
end
Yield to a block N times.
40000.times do
# SOLUTION?
end
for i in 1..n
n.times
1.upto(n)
(1..n).each
for i in 1..n
40000.times do
for i in 1 .. n do
n
end
end
n.times
40000.times do
n.times do
n
end
end
1.upto(n)
40000.times do
1.upto(n) do
n
end
end
(1..n).each
40000.times do
(1 .. n).each do
n
end
end
Return a value from a method.
n.times do
x = true
# SOLUTION? x
x = false
# SOLUTION? x
end
explicit return
fall through
explicit return
def sol_1 x
if x
return 1
else
return 2
end
end
n.times do
x = true
sol_1 x
x = false
sol_1 x
end
fall through
def sol_2 x
if x
1
else
2
end
end
n.times do
x = true
sol_2 x
x = false
sol_2 x
end
Get first element of Array.
array = [ :thing ]
n.times do
# SOLUTION?
end
array[0]
array.first
array[0]
array = [ :thing ]
n.times do
array[0]
end
array.first
array = [ :thing ]
n.times do
array.first
end
array[0]
is optimized on some platforms.array.first
should be optimized on all platforms.Get last element of Array.
array = [ :thing ]
n.times do
# SOLUTION?
end
array[-1]
array.last
array[-1]
array = [ :thing ]
n.times do
array[-1]
end
array.last
array = [ :thing ]
n.times do
array.last
end
array[-1]
is optimized on some platforms.array.last
should be optimized on all platforms.Build a String from parts.
foo = "foo"
bar = 42
n.times do
# SOLUTION?
end
String#+
String Interpolation
String#+
foo = "foo"
bar = 42
n.times do
"abc" + foo + "123" + bar.to_s
end
String Interpolation
foo = "foo"
bar = 42
n.times do
"abc#{foo}123#{bar}"
end
Output a String and Integer in a simple format
foobar = "foobar"
n.times do
# SOLUTION?
end
String#%
String interpolation
SprintfCompiler cached
String#%
foobar = "foobar"
n.times do
"%s, %d" % [ foobar, n ]
end
String interpolation
foobar = "foobar"
n.times do
"#{foobar}, #{n}"
end
SprintfCompiler cached
foobar = "foobar"
n.times do
SprintfCompiler.fmt("%s, %d", [ foobar, n ])
end
Construct a Symbol from a String.
foobar = "foobar"
n.times do
# SOLUTION?
end
String#to_sym
Dynamic Symbol
String#to_sym
foobar = "foobar"
n.times do
"#{foobar}123".to_sym
end
Dynamic Symbol
foobar = "foobar"
n.times do
:"#{foobar}123"
end
Enumerate elements while using a temporary or block variable.
array = (0 ... n).to_a.sort_by{|x| rand}
100000.times do
# SOLUTION?
end
Array#inject
Local variable
Array#inject
array = (0 ... n).to_a.sort_by{|x| rand}
100000.times do
array.inject({ }) { | hash, x | hash[x] = true; hash }
end
Local variable
array = (0 ... n).to_a.sort_by{|x| rand}
100000.times do
hash = { }
array.each { | x | hash[x] = true }
hash
end
Accumulate String parts of size N into one larger String.
parts = (0 ... 100).to_a.map{"a" * n}
str = ''
100.times do
# SOLUTION?
end
str += x
str << x
str += x
parts = (0 ... 100).to_a.map{"a" * n}
str = ''
100.times do
parts.each do | x |
str += x
end
end
str += x
is the same as:
str = (str + x)
str << x
parts = (0 ... 100).to_a.map{"a" * n}
str = ''
100.times do
parts.each do | x |
str << x
end
end
Accumulate String parts of size N into one larger String.
parts = (0 ... 100).to_a.map{"a" * n}
10000.times do
# SOLUTION?
end
str << x
parts.join
str << x
parts = (0 ... 100).to_a.map{"a" * n}
10000.times do
str = ''
parts.each do | x |
str << x
end
end
parts.join
parts = (0 ... 100).to_a.map{"a" * n}
10000.times do
str = parts.join("")
end
Is a value in a short, constant set?
# n = 2
x == 0 || x == 1
[ 0, 1 ].include?(x)
case x
when 0, 1
true
end
# ETC... TIMTOWTI!
x == y1 || ...
[ ... ].include?(x)
array.include?(x)
case x; when y1, y2 ...
case x; when *array
hash.key?(x)
x == y1 || ...
@array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
x == 0 # n == 1
x == 0 || x == 1 # n == 2
...
[ ... ].include?(x)
@array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
[ 0, 1 ].include?(x) # n == 2
array.include?(x)
@array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
ARRAY = [ 0, 1 ].freeze # n == 2
...
ARRAY.include?(x)
case x; when y1, y2 ...
@array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
case x
when 0, 1 # n == 2
true
end
case x; when *array
@array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
ARRAY = [ 0, 1 ].freeze
...
case x
when *ARRAY
true
end
hash.key?(x)
@array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
HASH = { 0 => true, 1 => true }.freeze
...
HASH.key?(x)
===
, not ==
.x == y
when n == 1.Is an element in a Array?
array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 2000).to_a.sort_by{|x| rand}
100.times do
try.each do | x |
# SOLUTION?
end
end
Array#include?
case x; when *array
hash.key?(x)
Array#include?
array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 2000).to_a.sort_by{|x| rand}
100.times do
try.each do | x |
array.include?(x)
end
end
case x; when *array
array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 2000).to_a.sort_by{|x| rand}
100.times do
try.each do | x |
case x
when *array
true
end
end
end
hash.key?(x)
array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 2000).to_a.sort_by{|x| rand}
100.times do
try.each do | x |
hash.key?(x)
end
end
#===
operator.Array#include?
is slower than MRI 1.8.6.Is a value in a constant set?
# n = 2
array = [ :foo, :bar ]
hash = { :foo => true, :bar => true }
set = Set.new([ :foo, :bar ])
...
array.include?(x)
hash.key?(x)
set.include?(x)
! (array & [ x ]).empty? # <== WTF?
array.include?(x)
hash.key?(x)
set.include?(x)
!(array&[x]).empty?
array.include?(x)
array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
1000.times do
try.each do | x |
array.include? x
end
end
hash.key?(x)
array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
1000.times do
try.each do | x |
hash.key?(x)
end
end
set.include?(x)
array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
1000.times do
try.each do | x |
set.include?(x)
end
end
!(array&[x]).empty?
array = (0 ... n).to_a.sort_by{|x| rand}
try = (0 ... 1000).to_a.map{|x| rand(n + n)}.sort_by{|x| rand}
1000.times do
try.each do | x |
! (array & [ x ]).empty?
end
end
!(Array&[x]).empty?
performs “too well”. (!!!)Evaluate a dynamic expression
x = 10
expr = "x * 2"
eval(expr, binding)
eval
cached lambda
eval
exprs = (0 ... 100).to_a.sort_by{|y| rand}.map{|y| "x * #{y}"}
x = 10
n.times do
exprs.each do | expr |
eval(expr, binding)
end
end
cached lambda
exprs = (0 ... 100).to_a.sort_by{|y| rand}.map{|y| "x * #{y}"}
x = 10
n.times do
exprs.each do | expr |
p = lambdas[expr] ||= eval(%Q{lambda{|x| #{expr}}})
p.call(x)
end
end
http://github.com/kstephens/ruby_code_tweaks