昨日はshogo82148さんでPerl 5.40からiterating over multiple values at a time機能が安定版になりましたでした。
今日は6日、7日のついでの投稿になります。申し訳ないです。
概要
JSON::PPのエンコードは二通りあります。
$json_text = encode_json $perl_scalar
$json_text = JSON::PP->new->utf8->encode($perl_scalar)
メソッドの説明ではこれらは一緒だけど、速さが違うとありましたので、どの程度違うのか調べることにします。
ソースコードはutf8で記述し、データには日本語を含むものとします。
比較するメソッド
- encode_json
- JSON::PP->new->utf8->encode
- 以上2つはJSON文字列をutf8としてエンコードします。
- Encode::encode_utf8( JSON::PP->new->utf8(0)->encode )
- JSON::PP->new->utf8(0)とすることで、utf8にエンコードせず、内部コードとして文字列が作られるので、さらにEncodeモジュールのencode_utf8を用いてutf8文字列を得ます
方法とコード(12月12日修正)
50レコードのデータを作成し、5000回エンコードし、その速度を比較します。
@mackee_wさんにコメントで教えていただきコードを修正しました。前のコードは文末にあります。
Benchmarkモジュールを使って書き換えてあります。コメントありがとうございました。コードが見やすくなりました。
#!perl
use v5.40;
use JSON::PP;
use utf8;
use Encode;
use Benchmark qw(timethese);
my @sum = (0, 0, 0);
my $d = [{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"}];
timethese(5000, {
'method1' => sub {encode_json($d)},
'method2' => sub {JSON::PP->new->utf8->encode($d)},
'method3' => sub {encode_utf8(JSON::PP->new->utf8(0)->encode($d))}
});
結果
Benchmark: timing 5000 iterations of Name1, Name2, Name3...
method1: 1 wallclock secs ( 1.55 usr + 0.00 sys = 1.55 CPU) @ 3232.06/s (n=5000)
method2: 2 wallclock secs ( 1.58 usr + 0.00 sys = 1.58 CPU) @ 3168.57/s (n=5000)
method3: 1 wallclock secs ( 1.47 usr + 0.00 sys = 1.47 CPU) @ 3405.99/s (n=5000)
メソッド | 順位 |
---|---|
encode_json | 2 |
JSON::PP->new->utf8->encode | 3 |
encode_utf8( JSON::PP->new->utf8(0)->encode ) |
1 |
まとめ
1件あたりの速度の違いは微々たるものです。
3種類比較し、3番目の方法「JSON::PPでutf8の文字列を得るのではなく、内部コードのJSON文字列とし、改めてEncodeモジュールでutf8にエンコード」が早いことに驚きました。
実験としては不備不足等あるかと存じます。コメント欄で指摘いただけるとありがたいです。
以上です。ありがとうございました。
謝辞
@mackee_wさん、ありがとうございます。あまりの便利さに震えました。コードもスッキリしましたし、Advent Calendarに参加して良かったと思います。ありがとうございました。
修正前のコードと結果
#!perl
use v5.40;
use JSON::PP;
use utf8;
use Encode;
use Time::HiRes qw/gettimeofday tv_interval/;
my @sum = (0, 0, 0);
my $d = [{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"},
{a=>1, b=>"テスト"}, {a=>1, b=>"試験"}, {a=>2, b=>"文字列"}, {a=>2, b=>"任意"}, {a=>3, b=>"仮文"}];
for(my $i=0; $i<5000; $i++){
&pGo;
}
sub pGo{
my $starttime = [gettimeofday];
my $json1 = encode_json($d);
my $raptime1 = tv_interval($starttime);
my $json2 = JSON::PP->new->utf8->encode($d);
my $raptime2 = tv_interval($starttime);
my $json3 = encode_utf8(JSON::PP->new->utf8(0)->encode($d));
my $raptime3 = tv_interval($starttime);;
$sum[0] += $raptime1;
$sum[1] += $raptime2-$raptime1;
$sum[2] += $raptime3-$raptime2;
}
printf("A:%0.6f\n",$sum[0]);
printf("B:%0.6f\n",$sum[1]);
printf("C:%0.6f\n",$sum[2]);
メソッド | 5000回処理時間(秒) | 順位 |
---|---|---|
encode_json | 1.602037 | 2 |
JSON::PP->new->utf8->encode | 1.610351 | 3 |
encode_utf8( JSON::PP->new->utf8(0)->encode ) |
1.481043 | 1 |