ithread を使って処理の高速化の例

Perl5.8 では、ithread というスレッドモデルが採用されました。XML や SOAP といった通信処理を書くと、応答を待っている時間が非常にもったいない。例えば、サイトをクロールするときとかは通信時間がバカにならないので、並列化は特に有効です。

ちょっとした実験をしてみたのですが、概ね良好な結果が得られたので、随所にスレッド処理を施そうと思います。
- スポンサーリンク -


例えば、Amazon Web Service の並列取得なんかを実験してみると、
#!/usr/bin/perl -w
 
use strict;
use LWP::Simple;
use XML::Simple;
use threads;
use Thread::Queue;

my @sites = (
    'http://xml.amazon.co.jp/onca/xml3?&dev-t=DAB7UJEE24RXR&t=drk7jp-22&AsinSearch=B0001FACT8,B0000UN56G,B0000084NK,B000094U3X,B00006YXVA,B000063EFE,B00004TJK5,B00005HTVZ&type=heavy&f=xml&locale=jp&page=1&sort=+salesrank',
    'http://xml.amazon.co.jp/onca/xml3?&dev-t=DAB7UJEE24RXR&t=drk7jp-22&AsinSearch=B0000UN56G,B0000084NK,B000094U3X,B00006YXVA,B000063EFE,B00004TJK5,B00005HTVZ&type=heavy&f=xml&locale=jp&page=1&sort=+salesrank',
    'http://xml.amazon.co.jp/onca/xml3?&dev-t=DAB7UJEE24RXR&t=drk7jp-22&AsinSearch=B0000084NK,B000094U3X,B00006YXVA,B000063EFE,B00004TJK5,B00005HTVZ&type=heavy&f=xml&locale=jp&page=1&sort=+salesrank',
);

my @threads;
my $queue = new Thread::Queue;

&get1;
&get2;

sub get1() {
	my $btime = time();
	print "TIME1=" .(time-$btime). "\n";
	my $idx=0;
	foreach my $site ( @sites ) {
		push @threads, threads->new(\&_search, $site, $idx++);
	}

	foreach (@threads) { $_->join; }

	foreach my $site ( @sites ) {
		my $xml = $queue->dequeue();
		print $xml, "\n";
	}
	print "TIME1=" .(time-$btime). "\n";
}

sub get2() {
	my $btime = time();
	print "TIME2=" .(time-$btime). "\n";
	my $idx=0;
	foreach my $site ( @sites ) {
		print $idx.":".length(LWP::Simple::get($site)), "\n";
		$idx++;
	}
	print "TIME2=" .(time-$btime). "\n";
}

sub _search {
	my $url = shift;
	my $idx = shift;

	$queue->enqueue( $idx.":".length( LWP::Simple::get($url) ) );
}

結果は、
TIME1=0
0:34853
2:26418
1:31282
TIME1=1
TIME2=0
0:34853
1:31282
2:26418
TIME2=4
となり、 ithread の方が3秒も速く終了して、その有効性が示せた。しかしながら、通信時間がかからない URL に対するアクセスの場合は、ithread を用いない方が高速だった。つまりは待ち時間よりもオーバーヘッドの方が大きいことになる。結局は Try&Error で最適な方法を選ぶしかないが、適材適所で ithread を用いると良い結果が得られることがわかった。
- スポンサーリンク -