2004年08月31日
Location::GeoToolの高速化(1)
Location::GeoToolの動作の重さがどうにかならないかという事に関して、利用者の方から示唆をいただいたりした事も有り、ちょっといくつか試して見ました。
その1としては、オブジェクトの生成に時間がかかっているのではないか、という指摘。
1つ2つの経緯度処理なら全く問題ないのだけど、何万何千と言う位置情報を処理するのに、いちいちオブジェクトを生成していては非常に処理が遅くなるのが問題。
解決方法としては、Jcodeのsetメソッドのように、オブジェクトの生成は行わずに、既存オブジェクトの中身だけ置き換えるメソッドを準備すれば、早くなるのではないかという示唆があって、実際示唆してくださった方はそういう拡張を行ってテストしてみてくださったのですが、100万件回して、毎回オブジェクト生成だと30秒弱、使いまわしだと10秒弱ですんだ、との事。
さっそくその結果を実装に反映しようと見てみると…随分前に作って忘れてたけど、よく見るとコンストラクタのcreate_coordって、クラスメソッドとしてもオブジェクトメソッドとしても呼べるように作ってあるわ…。
sub create_coord3d
{
my $self = shift;
$self = $self->_new() unless (ref($self)); <-このあたり
@{$self}{qw(lat long alt def_datum def_format source)} = @_;
当時はオブジェクト生成時の実行コストとか全く考えてなかったんで本当にたまたまなんだけど、これで改造しなくてもオブジェクトの使いまわしができますね。
というわけで、1つ目のLocation::GeoTool高速化としては、モジュール側の改造ではなく利用者側のTipsとして、
・大量の点を処理する場合は、create_coordオブジェクトはクラスメソッドとして呼ぶのではなく、オブジェクトメソッドとして、オブジェクトの使いまわしをする事
という結果が判りました。
試しにこちらでもテストしてみました。
20万回、都度オブジェクト生成とオブジェクト使い回しでテストしてみると、
テストコード:
use Location::GeoTool;
use Benchmark qw(timethese);timethese 1, {
'each_create' => sub {
for($i = 0; $i < 200000; $i++) {
Location::GeoTool->create_coord("35.00.00.000","135.00.00.000","wgs84","gpsone");
}
},
'obj_persist1' => sub {
my $obj = 'Location::GeoTool';
for($i = 0; $i < 200000; $i++) {
$obj = $obj->create_coord("35.00.00.000","135.00.00.000","wgs84","gpsone");
}
},
'obj_persist2' => sub {
my $obj = Location::GeoTool->create_coord("35.00.00.000","135.00.00.000","wgs84","gpsone");
for($i = 0; $i < 199999; $i++) {
$obj->create_coord("35.00.00.000","135.00.00.000","wgs84","gpsone");
}
},
}
結果:
Benchmark: timing 1 iterations of each_create, obj_persist1, obj_persist2...
each_create: 8 wallclock secs ( 7.77 usr + 0.00 sys = 7.77 CPU) @ 0.13/s (n=1)
obj_persist1: 3 wallclock secs ( 3.42 usr + 0.00 sys = 3.42 CPU) @ 0.29/s (n=1)
obj_persist2: 4 wallclock secs ( 3.28 usr + 0.00 sys = 3.28 CPU) @ 0.30/s (n=1)
というわけで、オブジェクト使い回しで倍近いパフォーマンスが出ました。
面白かったのは、$obj=$obj->…等と中身の移し変えをするだけでも、20万回も回すと結構なパフォーマンス差が出てる事。
論理上一緒だから書き易い方がいいだろう、とか、そんな安易なアレであんまり楽しすぎないほうがいいって事ですね。
でも、大元のオブジェクトは使い回せばいいとしても、OOP実現のためにいちいち生成しているオブジェクトはどうしよう。
例えば、$obj->format_mapion->datum_wgs84->arrayなんかの時の、format_mapion、datum_wgs84等のメソッド実行毎に生成しているオブジェクトの事。
こういうインタフェースのOOPをやろうと思えば、どうしてもオブジェクトを新規に生成せざるを得ない。
インターフェース的に参考にしたJcodeはどうしてるのかなあ…と見てみたら、結構すごい事やってた…。
Jcodeの場合、$obj->h2z->sjisとかやった場合、普通直感的には$objの内容自体は変化なく保存されると思うが、h2z を実行した時点で$objの中身そのものを修正し、その結果をメソッド戻り値として返している(つまりオブジェクトの新規生成コストはない)という実装になってた。
あまりにも非直感的だけど、Jcode的な用途の場合一方通行の変換が主なので、こういうのもありなのかなと。
でもLocation::GeoToolの場合、中央の1点をオブジェクトにして、そこを基準にその周辺数点の位置を計算したい、といった要件もありがちなので、メソッドに依存してオブジェクトが内容が変わってしまっても困る。
勢い、新規オブジェクトを生成せざるを得ず、実行コストが高まってしまう。
うーん、どうしたもんかね。
Posted with ecto
![[ここギコ!]](http://kokogiko.net/logo.png)



・コンピュータは2進法が効率的でとかいう話(とおりすがり)
・ジオメディア忘年会行ってきました(宋さんへ:kokogiko)
・コンピュータは2進法が効率的でとかいう話(kokogiko)
・コンピュータは2進法が効率的でとかいう話(まぐろ)
・コンピュータは2進法が効率的でとかいう話(名無し)
・コンピュータは2進法が効率的でとかいう話(dokasen)
・コンピュータは2進法が効率的でとかいう話(dokasen)
・Google未オルソ衛星画像にぶった切られた我が母校(maeda)
・ジオメディア忘年会行ってきました(宋)