PerlのDateTimeとTime::Pieceモジュールのベンチマーク
Perlで日付関連の処理をする代表的なモジュールにDateTimeというものがありますが、メモリ消費量が激しいのがずっと気になっていました。でで、Time::Pieceが5.10.1からPerlに標準添付になったという話を聞いて、乗り換えようかどうか検討しています。Perlメモ/Time::Pieceモジュール – Walrus, Digit.を見ると、DateTimeでできることは大体できるので、以下のユースケースでの速度面を測ってみます。
- use 時のメモリ使用量
- 現在日時でオブジェクトを生成する
- 日付オブジェクトに対する日付の加算
- 日付オブジェクト同士の減算(A – B して何日経ったかみたいな)
- 日付オブジェクト同士の比較
- 日付オブジェクトを文字列にする
環境は以下で、ベンチマークのスクリプトは最後に載せてあります。
- OS: Ubuntu 9.04 amd64
- Perl: 5.10.0 x86_64-linux-gnu-thread-multi
- 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, }; }
こちらもあわせてどうぞ
- Text::MicroTemplate 0.10で速度が速くなっている件
- PerlでAmazon Product Advertising APIのBrowseNodeLookupを行なう
- Text::MicroTemplateの速度を簡単にベンチマーク
コメント