0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PerlAdvent Calendar 2024

Day 11

JSON::PPのencodeメソッドの速度比較

Last updated at Posted at 2024-12-10

昨日は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
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?