# today there was a bit of discussion on using RMagick vs shelling out to
# convert to make thumbnails in the excellent paperclip plugin on github
#
# http://github.com/thoughtbot/paperclip/issues/closed/#issue/90
#
# oddly no one bothered to actually test the assertion that using the api
# should be faster or require less resources. this test does not test forking
# on a heavily loaded system but given that rmagick itself uses multiple
# threads to do processing (the image magick library actually - and these are
# native threads) i don't think it's relevant.
#
# the *important* thing to get about the below is just how easy it would be
# for paperclip to continue using the shell commands and easily make all the
# scaling parallel for a super easy speed boost. note that this is not true
# of using the api - it can only leverage a single ruby green thread so the
# naive attempt at making it parallel fails - the only way to make it parallel
# is, in fact, to create processes anyhow.
#
# my general rules for 'making shit faster' in ruby are
# - use processes
# - use many of them by forking
# or
# - use many of them by threading system calls
#
# the later (threading sys calls) works on all platforms including windoze to
# give easy parallel process management and speedup.
#
require 'benchmark'
require 'rubygems'
require 'RMagick'
gem 'threadify', '>= 1.3.0'
require 'threadify'
path = ARGV.shift or abort('no path')
n = Integer(ARGV.shift || 4)
scale_api = lambda do
img = Magick::Image.read(path).first
thumb = img.scale(0.25)
thumb.write("thumb.gif")
end
cmd = "convert -scale 25%x25% #{ path.inspect } thumb.gif"
scale_shl = lambda do
system(cmd) or abort("cmd:#{ cmd } failed with #{ $?.inspect }")
end
Benchmark.bm do |bm|
bm.report('api'){ n.times{ scale_api.call } }
bm.report('shl'){ n.times{ scale_shl.call } }
bm.report('threaded api'){ Threadify(n){ scale_api.call } }
bm.report('threaded shl'){ Threadify(n){ scale_shl.call } }
end
__END__
output from two sample runs - the first is on a small image and the second a
large one
cfp:~ > identify Pictures/arnold.jpg
Pictures/arnold.jpg JPEG 300x411 300x411+0+0 8-bit DirectClass 37.0117kb
cfp:~ > ruby a.rb Pictures/arnold.jpg 16
user system total real
api 4.850000 0.060000 4.910000 ( 5.022925)
shl 0.000000 0.020000 5.230000 ( 5.477109)
threaded api 4.860000 0.070000 4.930000 ( 5.103877)
threaded shl 0.020000 0.040000 5.380000 ( 2.981845)
cfp:~ > identify Pictures/A-is-for-axel.tif
Pictures/A-is-for-axel.tif TIFF 1623x2100 1623x2100+0+0 8-bit DirectClass 9.7514mb
cfp:~ > ruby a.rb Pictures/A-is-for-axel.tif 4
user system total real
api 36.850000 1.260000 38.110000 ( 39.744877)
shl 0.000000 0.000000 37.820000 ( 38.856584)
threaded api 36.640000 1.210000 37.850000 ( 38.913540)
threaded shl 0.070000 0.050000 53.730000 ( 30.936035)