2007ǯ05·î18Æü 03:30 [Edit]
ruby & perl - ·ÚÎÌ¥×¥í¥»¥¹¤òthread¤ÇÂåÍÑ
erlang¤ÇÍ£°ì˨¤¨¤ë·ÚÎÌ¥×¥í¥»¥¹¤Ç¤¹¤¬¡¢¤³¤ì¤Ïthread¤Ç¤âÈæ³ÓŪ´Êñ¤ËÂåÍѤϤǤ¤Þ¤¹¡£
Rubyist Magazine - Rubyist ¤Î¤¿¤á¤Î¾¸À¸ìõˬ ¡ÚÂè 10 ²ó¡Û Erlang¤Ç¾Ò²ð¤µ¤ì¤Æ¤¤¤¿Erlang Land¤Î¥Õ¥£¥Ü¥Ê¥Ã¥Á¿ô¤òÈ󯱴ü¤Ç·×»»¤¹¤ëÎã¤Ï¡¢ruby¤Ç½ñ¤¯¤È¤³¤ó¤Ê´¶¤¸¤Ë¤Ê¤ë¤Ç¤·¤ç¤¦¡£
thrfib.rb
require 'thread'
require 'Common'
def worker(n, q)
return Thread.new do
q.push("fib(#{n}) = #{fib(n)}")
end
end
def manager(n, q)
Thread.new do
n.times { puts q.shift }
end
end
nums = getrange(1, 28)
elapsed = timeit do
q = Queue.new;
t = manager(nums.length, q)
nums.reverse.each{ |x| worker(x, q) }
t.join
end
puts "Took #{elapsed} seconds."
system "ps ux -p $$";
¤³¤³¤Ç¡¢Common¤È¤¤¤¦¤Î¤Ï¡¢ÉáÄÌ¤ËÆ±´üŪ¤Ë·×»»¤¹¤ë¾ì¹ç¤È¤Î¶¦Ä̹à¤ò¤Þ¤È¤á¤¿¤â¤Î¤Ç¤¹¡£
Common.rb
def fib(n)
n < 2 ? 1 :fib(n - 2) + fib(n - 1)
end
# yikes! Range is not an array!
class Range
def to_array()
a = []
self.each{ |x| a.push(x) }
return a
end
end
def timeit(&block)
def now()
t = Time.now
t.tv_sec + t.tv_usec.to_f / 1e6
end
started = now()
block.call
now() - started
end
def getrange(h, t)
head = ARGV.size > 0 ? ARGV.shift.to_i : h
tail = ARGV.size > 0 ? ARGV.shift.to_i : t
(head..tail).to_array
end
¤Ç¡¢Æ±´üŪ¤Ë·×»»¤¹¤ë¾ì¹ç¤Ï¤³¤¦¡£
seqfib.rb
require 'Common'
def work(n)
"fib(#{n}) = #{fib(n)}"
end
head = ARGV.size > 0 ? ARGV.shift.to_i : 1
tail = ARGV.size > 0 ? ARGV.shift.to_i : 28
nums = (head..tail).to_array
elapsed = timeit do
nums.reverse.each{ |x| puts work(x) }
end
puts "Took #{elapsed} seconds."
system "ps ux -p $$";
¤ä¤Ã¤Æ¤ß¤ë¤È¤ï¤«¤ê¤Þ¤¹¤¬¡¢threadÈǤϳΤ«¤ËÈ󯱴ü¤Ç¼Â¹Ô¤µ¤ì¤Æ¤¤¤Þ¤¹¡£
fib(19) = 6765 fib(21) = 17711 .... fib(27) = 317811 fib(28) = 514229 Took 1.62463402748108 seconds. USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND root 493 0.0 -0.0 27264 368 p1 R+ 3:07AM 0:00.01 ps ux -p 493
¸«¤Æ¤ï¤«¤ë¤È¤ª¤ê¡¢¤³¤³¤Ç¤Ï¥á¥Ã¥»¡¼¥¸¤ÎÁ÷ÉÕ¤ËQueue¥¯¥é¥¹¤ò»È¤Ã¤Æ¤¤¤Þ¤¹¡£¤³¤ì¤Ëpush()¤¹¤ë¤Î¤¬erlang¤ÎPID ! Message¤Ë¡¢¤½¤³¤«¤éshift()¤¹¤ë¤Î¤¬receive Message -> blah, end.ÁêÅö¤¹¤ë¤ï¤±¤Ç¤¹¡£
¤â¤¦°ì¤Ä¸«¤Æ¤ï¤«¤ë¤Î¤Ï¡¢thread¤Èqueue¤ò»È¤Ã¤¿ÊÂÎó½èÍý¤Ç¤Ï¡¢¤½¤Î¤¿¤á¤ÎÆÃÊ̤ʹ½Ê¸¤ò°ìÀÚÍøÍѤ·¤Æ¤¤¤Ê¤¤¤³¤È¤Ç¤¹¡£thread¤Ç¼Â¹Ô¤¹¤ë¤â¤Î¤Ïblock¤ÇÅϤ·¡¢thread¤Ï¥ª¥Ö¥¸¥§¥¯¥È¤È¤·¤ÆÀ¸À®¤¹¤ë¡£¤¹¤³¤Ö¤ëľ´¶Åª¤Ç¤¹¡£
¤Á¤Ê¤ß¤Ë¡¢-Dthread¥ª¥×¥·¥ç¥óÉÕ¤¤Ç¥³¥ó¥Ñ¥¤¥ë¤µ¤ì¤¿perl¤Ç¤Ï¡¢¾å¤Îruby¤ÎÎã¤ò¤½¤Î¤Þ¤ÞÁÇľ¤Ë°Ü¿¢¤·¤ÆÆ°¤«¤»¤Þ¤¹¡£
sub fib{
my $n = shift;
return $n <= 1 ? 1 : fib($n - 2) + fib($n - 1);
}
sub timeit(&){ # for benchmark
require Time::HiRes;
my $coderef = shift;
my $started = Time::HiRes::time();
$coderef->();
return Time::HiRes::time() - $started;
}
sub getrange{
my ($h, $t) = @_;
my $head = shift @ARGV || $h;
my $tail = shift @ARGV || $t;
( $head .. $tail );
}
1;
seqfib.pl
use strict;
use warnings;
use Common;
sub work{
my $n = shift;
"fib($n) = " . fib($n);
}
my @nums = getrange(1, 28);
my $elapsed = timeit {
print work($_), "\n" for reverse @nums;
};
print "Took $elapsed seconds.\n";
system "ps ux -p $$";
thrfib.pl
use strict;
use warnings;
use threads;
use Thread::Queue;
use Common;
sub worker {
my ($n, $q) = @_;
threads->new(sub {
$q->enqueue("fib($n) = " . fib($n));
} => shift)->detach;
}
sub manager {
my ($ntask, $q) = @_;
threads->new(sub {
print $q->dequeue, "\n" while($ntask--);
});
}
my @nums = getrange(1, 28);
my $elapsed = timeit {
my $q = Thread::Queue->new;
my $mgr = manager(@nums+0, $q);
worker($_, $q) for reverse @nums;
$mgr->join();
};
print "Took $elapsed seconds.\n";
system "ps ux -p $$";
¤·¤«¤âÌÌÇò¤¤¤³¤È¤Ë¡¢¼ê¸µ¤Î´Ä¶¤Ç¤ÏthreadÈǤÎÊý¤¬Æ±´üÈǤè¤ê¤â¹â®¤Ç¤·¤¿¡£¤³¤ì¤Ï¤ª¤½¤é¤¯threadÈǤÎÊý¤¬·ë²ÌŪ¤Ë¥á¥â¥ê¡¼¤ò¤Þ¤È¤á¤Æ³ÎÊݤ·¤Þ¤È¤á¤Æ²òÊü¤¹¤ë¤³¤È¤Ë¤Ê¤ë¤¿¤á¤À¤È»×¤ï¤ì¤Þ¤¹¡£
% ~/bleedperl/bin/perl5.9.5 seqfib.pl .... Took 2.82808804512024 seconds. USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND dankogai 290 99.6 -0.1 36624 2196 p1 S+ 3:29AM 0:02.85 /Users/dan % ~/bleedperl/bin/perl5.9.5 thrfib.pl .... Took 1.78629589080811 seconds. USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND dankogai 293 0.1 -0.4 39716 9292 p1 S+ 3:33AM 0:03.02 /Users/dan
¤È¤Ï¤¤¤¨¡¢perl 5¤Ç¤Ï¸½»þÅÀ¤Ç¤Ïthread¤Ï¥Ç¥Õ¥©¥ë¥È¤Çoff¤Ç¡¢¤Þ¤¿°ÂÄêÅÙ¤âOS¤Î¤è¤Ã¤Æ¤Þ¤Á¤Þ¤Á¤Ç¤·¤¿¡£¤·¤«¤·¿·¤·¤¤¥Ð¡¼¥¸¥ç¥ó¤Û¤É°ÂÄꤷ¤Æ¤¤Æ¤¤¤Æ¡£Íè¤ë¤Ù¤5.10¤Ç¤Ïruby¤Ê¤ß¤Ë°Â¿´¤·¤Æ»È¤¨¤ë¤â¤Î¤Ë¤Ê¤ë¤Î¤Ç¤Ï¤Ê¤¤¤«¤È´üÂÔ¤·¤Æ¤¤¤Þ¤¹¡£¿·µ¬¤Ëperl¤ò¥³¥ó¥Ñ¥¤¥ë¤·¤Æ¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ëµ¡²ñ¤¬¤¢¤ëÊý¤Ï¡¢À§È󤪻¤ò¡£¤¿¤À¤·¤Ð¤ê¤Ð¤ê»È¤¦¤Î¤Ç¤¢¤ì¤Ð¡¢5.8.8¤Ç¤Ï¤Ê¤¯5.9.5¤ÎÊý¤ò¡£
¸«¤Æ¤ÎÄ̤ꡢthread¤Èqueue¤ò»È¤Ã¤¿ÊÂÎó½èÍý¤È¤¤¤¦¤Î¤Ï¡¢OO¤È¤ÎÁêÀ¤¬Èó¾ï¤Ë¤¤¤¤¾å¡¢¥³¡¼¥É¤âľ´¶Åª¤Ë½ñ¤±¤Þ¤¹¡£thread¡Ö¤ò¡×¼ÂÁõ¤¹¤ë¤Î¤ÏÌÌÅݤǤ⡢thread¡Ö¤Ç¡×¼ÂÁõ¤¹¤ë¤Î¤Ï¤¹¤³¤Ö¤ë³Ú¤Ê¤Î¤Ç¤¹¡£queue¤Ç¥á¥Ã¥»¡¼¥¸¤ò¼õ¤±ÅϤ¹¤è¤¦¤Ë¤¹¤ì¤Ð¡¢¥Ç¥Ã¥É¥í¥Ã¥¯¤Î¿´ÇÛ¤â¤Û¤È¤ó¤É¤¢¤ê¤Þ¤»¤ó¤·¡¢»ö¼Â¾å¤Îshared nothing (but the queue)¤¬¼Â¸½¤µ¤ì¤Æ¤¤¤Þ¤¹¤·¡£
erlang¥Á¥Ã¥¯¤Ë¿ôËü¤È¤¤¤¦¤Î¤Ï¤µ¤¹¤¬¤Ë¤¤Ä¤¤¤Î¤Ç¤¹¤¬¡¢¿ôÉ´thread¤°¤é¤¤¤Ê¤éruby¤âperl¤â¤«¤Ê¤ê»È¤¤Êª¤Ë¤Ê¤ë¤È¤¤¤¦¤Î¤¬°õ¾Ý¤Ç¤¹¡£
¤È¤Ï¤¤¤¨¡¢LL¤Ë¤ª¤±¤ëthread programming¤È¤¤¤¦¤Î¤Ï¼ÂÎ㤬¾¯¤Ê¤¤¤Î¤â»ö¼Â¡£Java¤Ê¤É¤ÈÈæ³Ó¤¹¤ë¤ÈÆÃ¤Ë¤½¤¦¤Ç¤¹¡£¤³¤ì¤«¤é¾¯¤·¤Å¤Ä¼ÂÎã¤ò¾å¤²¤Æ¤¤¤±¤ì¤Ð¤È»×¤¤¤Þ¤¹¡£
Dan the Man with Too Many Threads to Join
¤³¤Îµ»ö¤Ø¤Î¥È¥é¥Ã¥¯¥Ð¥Ã¥¯URL
to_a¤À¤Ã¤¿¤Î¤«¡£
Ä̤ꤹ¤¬¤ê¤µ¤ó¡¢
¥³¥Ô¥Ú¤ÎÈϰϤ«¤éºÇ¸å¤Î¹Ô¤¬È´¤±¤Æ¤¿¤è¤¦¤Ç¤¹¡£
¤¤¤º¤ì¤ârange¤Ë¤Þ¤Ä¤ï¤ëÌäÂê¡£
Dan the Occasional Ruby Speaker
Package Common;
¤¬¤Ê¤¤¤Ç¤¹¤Í¡£

