Perlで日付関連の処理をする代表的なモジュールにDateTimeというものがありますが、メモリ消費量が激しいのがずっと気になっていました。でで、Time::Pieceが5.10.1からPerlに標準添付になったという話を聞いて、乗り換えようかどうか検討しています。Perlメモ/Time::Pieceモジュール - Walrus, Digit.を見ると、DateTimeでできることは大体できるので、以下のユースケースでの速度面を測ってみます。
環境は以下で、ベンチマークのスクリプトは最後に載せてあります。
- DateTime 0.51
- Time::Piece 1.15
use 時のメモリ使用量
こちらのgtop.plを使って測ります。
$ gtop.pl 'use DateTime'
10.2M : use DateTime
$ gtop.pl 'use Time::Piece'
2.5M : use Time::Piece
おおお、なんと4分の1!
現在日時でオブジェクトを生成する
$ ./benchmark_datetime.pl now
Benchmark: running now_datetime, now_time_piece for at least 3 CPU seconds...
now_datetime: 4 wallclock secs ( 3.03 usr + 0.00 sys = 3.03 CPU) @ 3149.83/s (n=9544)
now_time_piece: 2 wallclock secs ( 2.58 usr + 0.53 sys = 3.11 CPU) @ 52694.86/s (n=163881)
Rate now_datetime now_time_piece
now_datetime 3150/s -- -94%
now_time_piece 52695/s 1573% --
15倍!
日付オブジェクトに対する日付の加算
$ ./benchmark_datetime.pl add
Benchmark: running add_datetime, add_time_piece for at least 3 CPU seconds...
add_datetime: 3 wallclock secs ( 3.05 usr + 0.00 sys = 3.05 CPU) @ 1853.44/s (n=5653)
add_time_piece: 3 wallclock secs ( 2.76 usr + 0.42 sys = 3.18 CPU) @ 54969.81/s (n=174804)
Rate add_datetime add_time_piece
add_datetime 1853/s -- -97%
add_time_piece 54970/s 2866% --
Time::Pieceの圧倒的勝利。28倍!
日付オブジェクト同士の減算
$ ./benchmark_datetime.pl subtract
Benchmark: running subtract_datetime, subtract_time_piece for at least 3 CPU seconds...
subtract_datetime: 3 wallclock secs ( 3.00 usr + 0.00 sys = 3.00 CPU) @ 4065.00/s (n=12195)
subtract_time_piece: 4 wallclock secs ( 3.15 usr + 0.00 sys = 3.15 CPU) @ 132329.84/s (n=416839)
Rate subtract_datetime subtract_time_piece
subtract_datetime 4065/s -- -97%
subtract_time_piece 132330/s 3155% --
引き算もTime::Pieceの方が圧倒的に速いですね。
日付オブジェクト同士の比較
$ ./benchmark_datetime.pl compare
Benchmark: running compare_datetime, compare_time_piece for at least 3 CPU seconds...
compare_datetime: 3 wallclock secs ( 3.04 usr + 0.00 sys = 3.04 CPU) @ 47709.21/s (n=145036)
compare_time_piece: 4 wallclock secs ( 3.09 usr + -0.01 sys = 3.08 CPU) @ 173623.70/s (n=534761)
Rate compare_datetime compare_time_piece
compare_datetime 47709/s -- -73%
compare_time_piece 173624/s 264% --
日付オブジェクトを文字列にする
$ ./benchmark_datetime.pl stringify
Benchmark: running stringify_datetime, stringify_time_piece for at least 3 CPU seconds...
stringify_datetime: 3 wallclock secs ( 3.00 usr + 0.00 sys = 3.00 CPU) @ 44470.33/s (n=133411)
stringify_time_piece: 3 wallclock secs ( 2.45 usr + 0.66 sys = 3.11 CPU) @ 116681.35/s (n=362879)
Rate stringify_datetime stringify_time_piece
stringify_datetime 44470/s -- -62%
stringify_time_piece 116681/s 162% --
まとめ
総じてDateTimeよりTime::Pieceの方が高い性能を叩き出しました。速度にシビアな状況ではTime::Pieceを使った方が良いと感じました。こういう罠もあるみたいなので気をつけなくてはいけないところもありますが... インタフェースはどちらも綺麗に出来ているので使い勝手としては同じぐらいかなと思います。それにしてももっと速くTime::Pieceを検証しておけばよかったと思う今日この頃です。
ベンチマークスクリプト(benchmark_datetime.pl)
#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw(cmpthese timethese);
use DateTime;
use Time::Piece;
use Time::Seconds;
my $timezone = DateTime::TimeZone->new(name => 'local');
#----------------------#
# now
#----------------------#
sub now_datetime {
my $now = DateTime->now(time_zone => $timezone);
}
sub now_time_piece {
my $now = localtime;
}
#----------------------#
# add
#----------------------#
my $add_dt = DateTime->now(time_zone => $timezone);
sub add_datetime {
$add_dt->add(days => 1);
}
my $add_tp = localtime;
sub add_time_piece {
$add_tp += ONE_DAY;
}
#----------------------#
# subtract
#----------------------#
my $sub_dt1 = DateTime->now(time_zone => $timezone);
my $sub_dt2 = DateTime->new(
year => 2008,
month => 12,
day => 1,
);
sub subtract_datetime {
my $dur = $sub_dt1->subtract_datetime($sub_dt2);
}
my $sub_tp1 = localtime;
my $sub_tp2 = Time::Piece->strptime('2008-12-01', '%Y-%m-%d');
sub subtract_time_piece {
my $sec = $sub_tp1 - $sub_tp2;
}
#----------------------#
# compare
#----------------------#
my $compare_dt1 = DateTime->now(time_zone => $timezone);
my $compare_dt2 = DateTime->now(time_zone => $timezone);
sub compare_datetime {
my $result = DateTime->compare($compare_dt1, $compare_dt2) <= 0;
}
my $compare_tp1 = localtime;
my $compare_tp2 = localtime;
sub compare_time_piece {
my $result = $compare_tp1 <= $compare_tp2;
}
#----------------------#
# stringify
#----------------------#
my $now_dt = DateTime->now(time_zone => $timezone);
sub stringify_datetime {
$now_dt->strftime("%Y-%m-%d");
}
my $now_tp = localtime;
sub stringify_time_piece {
$now_tp->strftime("%Y-%m-%d");
}
#----------------------#
# main
#----------------------#
my $mode = shift @ARGV || 'now';
my $count = shift @ARGV || -3;
if ($mode eq 'now') {
cmpthese timethese $count, {
'now_datetime' => &now_datetime,
'now_time_piece' => &now_time_piece,
};
} elsif ($mode eq 'add') {
cmpthese timethese $count, {
'add_datetime' => &add_datetime,
'add_time_piece' => &add_time_piece,
};
} elsif ($mode eq 'subtract') {
cmpthese timethese $count, {
'subtract_datetime' => &subtract_datetime,
'subtract_time_piece' => &subtract_time_piece,
};
} elsif ($mode eq 'compare') {
cmpthese timethese $count, {
'compare_datetime' => &compare_datetime,
'compare_time_piece' => &compare_time_piece,
};
} elsif ($mode eq 'stringify') {
cmpthese timethese $count, {
'stringify_datetime' => &stringify_datetime,
'stringify_time_piece' => &stringify_time_piece,
};
}
[rakuten]book:13309692[/rakuten]