Rubyでマルチコアプログラミング!
一眼レフを買ってから写真を撮りまくってるonodesです.
いつも写真をネット上に公開するのにフォト蔵とFlickr(パス忘れて使えない)、zenphoto(
家のサーバ)を使っています.
旧サーバ(シングルコア)
zenphotoはPHPで書かれているwebアルバムソフトなんですが、サムネイルを動的に生成します.1回目は動的、二回目以降はサムネをキャッシュしてそこから呼び出す形を取るんですが・・・このzenphotoのキャッシュを作るには2つ方法があって
- 全部のページを開く
- ブラウザから管理なのでブラウザ管理画面を開いてそこのキャッシュを作る(ブラウザつけっぱ)
の二種類です.
常にブラウザつけてるのもあれですし、PHPの最大応答時間に引っかかることもある・・・のかな?
なのでいつものRubyを使ってzenphotoのサムネを生成してみました.
zenphotoでは
/zenphoro/albums/albumに写真が保存されます.キャッシュは
/zenphoto/cache/albumです.
つまり
albumsの写真をサムネ化してcacheに保存してやれば良い.
そしてサムネ写真は二種類必要です.
今回のプログラムは作成先のフォルダが作られていること、設定が初期状態であることの元作成しました.
require 'rubygems' gem PLATFORM =='java'? 'rmagick4j' : 'rmagick' require 'RMagick' #require 'magickwand' dirname = ARGV.to_s.chomp def run_gc # fDisabled = GC.enable # GC.start # GC.disable if fDisabled end open(dirname+"index.html","a").close #dir = Dir.open(dirname) i = 0 infile = [] new_dir = dirname.sub('albums','cache') #fp = popen("mkdir "+newdir) open(new_dir+"index.html","a").close dir = Dir.open(new_dir) ar_file_count = 0 new_file_count = 0 dir.each{|filename| next if filename =='index.html' || filename == '.' || filename == '..' || !(filename.to_s.include?('thumb.jpg')) infile<<filename.to_s[0,8] + '.jpg' } p infile.sort dir = Dir.open(dirname) count = 0 dir.each{|filename| next if filename=='.' || filename =='..' || filename == 'index.html' count += 1 } dir.each{ |filename| next if filename == '.' || filename == '..' || filename == 'index.html' puts filename if infile.include?(filename.to_s) puts 'fileOK!' next end puts '----------------' puts filename + ' => start' f1 = File.basename(filename) + '_100_cw85_ch85_thumb.jpg' f2 = File.basename(filename) + '_595.jpg' puts new_dir new_filename1 = new_dir + f1 new_filename2 = new_dir + f2 img = Magick::Image::read(dirname + filename).first new_img1 = img.resize(85,85) new_img1.write(new_filename1) #IO.popen("convert -resize 80x80 " + dirname+filename +" " + new_filename1 ) puts 'create => ' + f1 new_img2 = img.resize(595,398) new_img2.write(new_filename2) puts 'create => ' + f2 #IO.popen("convert -resize 595x398 " + dirname+filename +" " + new_filename2 ) run_gc #puts #puts i.to_s + " / " + count.to_s #puts ((i/count.to_f)*100).to_s + "%" #i+=1 } puts 'end and ' + i.to_s + ' files'
コメントアウトされてますが!
def run_gc # fDisabled = GC.enable # GC.start # GC.disable if fDisabled end
このRubyでImageMagickのRMagickというものにはバグがあり、メモリがリークしてしまいます.その結果としてRubyのGCを手動で動かしています.
新サーバ
onodes新サーバは仮想クアッドコアなのでマルチスレッドでこのプログラムを動作させたいわけです.Ruby1.8、Ruby1.9ともにネイティブスレッドには対応していないのでJavaVMが使えるjRubyでマルチスレッド対応にしたいと思います.
急いで作ったのでいいソースではないですがgithubにおいてあります.
http://github.com/onodes/thumbrb
#start.rb #jruby start.rb /path require 'rubygems' gem PLATFORM =='java'?'rmagick4j' : 'rmagick' require'RMagick' require'thumb' require 'pp' require 'thread' q = Queue.new dir_r = ARGV.to_s.chomp dir_w = dir_r.gsub("albums","cache") ary = Dir::glob(dir_r + "*.{jpg,JPG}").map{|filename| Thumb.new(filename)} puts puts puts "-"*30 puts "-"*3 + "For zenphoto On PHP Web Album" + "-"*3 puts "Created by onodes 2009-2010" puts puts "-"*30 sleep 1.5 ary.each{|r| q.push(r) } t1 = Thread.new{ while(!q.empty?) print "Thread1 : " instance = q.pop instance.convert end self.kill } t2 = Thread.new{ while(!q.empty?) print "Thread2 : " instance = q.pop instance.convert end self.kill } t3 = Thread.new{ while(!q.empty?) print "Thread3 : " instance = q.pop instance.convert end self.kill } t1.join t2.join t3.join puts "End"
#thumb.rb require 'rubygems' gem PLATFORM == 'java'? 'rmagick4j':'rmagick' require 'RMagick' class Thumb def initialize(path_r,opt='') @path_r = path_r @path_w = path_r.gsub("albums","cache") end def rename(add) dirname + '/' + filename + add + extname end def convert img = Magick::Image::read(@path_r).first img.resize(85,85).write(rename('_100_cw85_ch85_thumb')) img.resize(595,398).write(rename('_595')) puts filename+"created" end private def extname @extname ||= File.extname(@path_w) end def filename @filename ||= File.split(@path_w)[1].gsub(extname,"") end def dirname @dirname ||= File.dirname(@path_w) end end
これで
jruby start.rb /写真ファイルのディレクトリ名
とやると
そのフォルダ内の(今はjpg)のファイルのサムネが作られます.