ホーム > Perl > Text::MicroTemplateの速度を簡単にベンチマーク

Text::MicroTemplateの速度を簡単にベンチマーク

2009/11/15 追記tokuhiromさんのコメントを受けて、Text::MicroTemplate以外のテンプレートファイルにHTMLエスケープの処理を追加してベンチマークを取り直しています。

Perlのテンプレートエンジンでどれを使おうか悩んでいるので、Text::MicroTemplateをはじめとする以下のテンプレートエンジンの速度を簡単にベンチマークしてみました。

下記の要因で単純に比較できない部分もあるので、これを鵜呑みにしないでなるべく自身のユースケースの延長でもベンチマークを取ることをお奨めします。あくまで参考値ということで。

  • そもそも持っている機能が全然違うので単純に比較できない
  • 実際のテンプレートファイルはもっと複雑なはず
  • utf8 flagの処理入れる場合もある

ではとりあえず結果から。

キャッシュなし

$ perl template_speed_file.pl 3000 0
Benchmark: timing 3000 iterations of HT, HT::Compiled, HT::Pro, MT, TT...
        HT:  5 wallclock secs ( 4.60 usr +  0.09 sys =  4.69 CPU) @ 639.66/s (n=3000)
HT::Compiled: 10 wallclock secs (10.56 usr +  0.10 sys = 10.66 CPU) @ 281.43/s (n=3000)
   HT::Pro:  1 wallclock secs ( 0.20 usr +  0.04 sys =  0.24 CPU) @ 12500.00/s (n=3000)
            (warning: too few iterations for a reliable count)
        MT:  2 wallclock secs ( 2.39 usr +  0.07 sys =  2.46 CPU) @ 1219.51/s (n=3000)
        TT: 10 wallclock secs ( 9.65 usr +  0.17 sys =  9.82 CPU) @ 305.50/s (n=3000)
                Rate HT::Compiled          TT          HT          MT    HT::Pro
HT::Compiled   281/s           --         -8%        -56%        -77%       -98%
TT             305/s           9%          --        -52%        -75%       -98%
HT             640/s         127%        109%          --        -48%       -95%
MT            1220/s         333%        299%         91%          --       -90%
HT::Pro      12500/s        4342%       3992%       1854%        925%         --

キャッシュあり

コードを見てもらえばわかるのですが、「キャッシュあり」とは具体的には

  • テンプレートのインスタンスを作るのは最初の1回だけ(キャッシュなしの場合は毎回作っている)
  • テンプレートエンジンに対して、「キャッシュあり」とコンストラクタで指令

ということになります。

$ perl template_speed_file.pl 3000 1
Benchmark: timing 3000 iterations of HT, HT::Compiled, HT::Pro, MT, TT...
        HT:  3 wallclock secs ( 2.69 usr +  0.00 sys =  2.69 CPU) @ 1115.24/s (n=3000)
HT::Compiled:  0 wallclock secs ( 0.28 usr +  0.00 sys =  0.28 CPU) @ 10714.29/s (n=3000)
            (warning: too few iterations for a reliable count)
   HT::Pro:  0 wallclock secs ( 0.13 usr +  0.02 sys =  0.15 CPU) @ 20000.00/s (n=3000)
            (warning: too few iterations for a reliable count)
        MT:  1 wallclock secs ( 0.22 usr +  0.01 sys =  0.23 CPU) @ 13043.48/s (n=3000)
            (warning: too few iterations for a reliable count)
        TT:  1 wallclock secs ( 1.84 usr +  0.00 sys =  1.84 CPU) @ 1630.43/s (n=3000)
                Rate          HT          TT HT::Compiled          MT    HT::Pro
HT            1115/s          --        -32%         -90%        -91%       -94%
TT            1630/s         46%          --         -85%        -87%       -92%
HT::Compiled 10714/s        861%        557%           --        -18%       -46%
MT           13043/s       1070%        700%          22%          --       -35%
HT::Pro      20000/s       1693%       1127%          87%         53%         --
  • HTML::Template::Proが爆速!
  • Text::MicroTemplateは、キャッシュなしだとそこそこ、キャッシュありはかなり速い部類に入るようです。キャッシュありだとHTML::Template::Proには及ばないものの、かなり速いです。
  • HTML::Template::Compiledはキャッシュを無効にするとTTより遅いという結果ですが、キャッシュを有効にすると猛烈に速くなるようです。ソースが追えてないのですが、中でガチンコにキャッシュしてるのでしょうか。
  • たぶん一番使われているTTはよく「遅い」と言われていますが、キャッシュを有効にすると意外にもHTML::Templateより速くなりました。

というのがポイントだと思います。この結果だけで判断すると、HTML::Template::Proは神がかり的な速さなのですが、そもそもPerlのコードをテンプレートに記述できず自由度は低いので(*1)、使う場合にはそれなりに不便さを覚悟した方がよいと思います。「便利さ」という点だとText::MicroTemplateはテンプレート内にPerlのコードが書ける分かなり自由度が高い、かつ速度もいい感じでバランスが取れていると言えます。

*1) Perlのコードをテンプレートに書けてしまっていいのかどうかは使う人次第だと思いますが

以下にソースを載せておきます。テストに使ったマシンはUbuntu 9.04, perl 5.10.0, CPUが Athlon Dual Core Processor 5050e です。

template_speed_file.pl

#!/usr/bin/env perl
 
use strict;
use warnings;
use HTML::Template;
use HTML::Template::Compiled speed => 1;
use HTML::Template::Pro;
use Template;
use Text::MicroTemplate::File;
 
use Benchmark qw(timethese cmpthese);
 
my @LANGUAGES = (
    { language => 'Perl', ll => 1 },
    { language => 'Ruby', ll => 1 },
    { language => 'Python', ll => 1 },
    { language => 'PHP', ll => 1 },
    { language => 'Java' },
    { language => 'C' },
    { language => 'C++' },
    { language => 'C#' },
    { language => 'VB' },
    { language => 'VB.NET' },
    { language => 'ASP.NET' },
    { language => 'Delphi' },
    { language => 'Erlang' },
    { language => 'Scala', ll => 1 },
    { language => 'Go' },
);
my $count = shift @ARGV || 1000;
my $cache = shift @ARGV || 0;
 
my $mt = undef;
sub mt {
    my %args = (use_cache => $cache);
    if ($cache) {
        $mt ||= Text::MicroTemplate::File->new(%args);
    } else {
        $mt = Text::MicroTemplate::File->new(%args);
    }
 
    my $s = $mt->render_file(
        'template_speed_file.mt',
        {
            page_title => 'LL Programming languages',
            languages => \@LANGUAGES,
        }
    )->as_string;
}
 
my $ht = undef;
sub ht {
    my %args = (
        filename => 'template_speed_file.ht',
        case_sensitive => 1,
        die_on_bad_params => 0,
        cache => $cache,
    );
    if ($cache) {
        $ht ||= HTML::Template->new(%args);
    } else {
        $ht = HTML::Template->new(%args);
    }
    $ht->param(
        page_title => 'LL Programming languages',
        languages => \@LANGUAGES,
    );
    my $s = $ht->output;
}
 
my $htc = undef;
sub htc {
    my %args = (
        filename => 'template_speed_file.ht',
        case_sensitive => 1,
        die_on_bad_params => 0,
        cache => $cache,
    );
    if ($cache) {
        $htc ||= HTML::Template::Compiled->new(%args);
    } else {
        $htc = HTML::Template::Compiled->new(%args);
    }
    $htc->param(
        page_title => 'LL Programming languages',
        languages => \@LANGUAGES,
    );
    my $s = $htc->output;
}
 
my $htp = undef;
sub htp {
    my %args = (
        filename => 'template_speed_file.ht',
        case_sensitive => 1,
        die_on_bad_params => 0,
        cache => $cache,
    );
    if ($cache) {
        $htp ||= HTML::Template::Pro->new(%args);
    } else {
        $htp = HTML::Template::Pro->new(%args);
    }
    $htp->param(
        page_title => 'LL Programming languages',
        languages => \@LANGUAGES,
    );
    my $s = $htp->output;
}
 
my $tt = undef;
sub tt {
    if ($cache) {
        $tt ||= Template->new(
            CACHE_SIZE => $cache ? undef : 0,
        );
    } else {
        $tt = Template->new;
    }
    $tt->process(
        'template_speed_file.tt',
        {
            page_title => 'LL Programming languages',
            languages => \@LANGUAGES,
        },
        \my $out,
    ) or die $tt->error() . "\n";
}
 
# main
my $comp = timethese(
    $count,
    {
        'MT' => \&mt,
        'HT' => \&ht,
        'HT::Pro' => \&htp,
        'HT::Compiled' => \&htc,
        'TT' => \&tt,
    }
);
cmpthese $comp;

template_speed_file.mt – Text::MicroTemplate用のファイル

? my $p = $_[0];
<html>
<head><title>Programming languages</title></head>
<body>
<h1><?= $p->{page_title} ?></h1>
<br />
<ul>
? for my $language (@{ $p->{languages} }) {
<li><?= $language->{language} ?></li>
? }
</ul>
</body>
</html>

template_speed_file.ht – HTML::Template::*用のファイル

<html>
<head><title>Programming languages</title></head>
<body>
<h1><TMPL_VAR NAME=page_title ESCAPE=HTML></h1>
<br />
<ul>
<TMPL_LOOP NAME=languages>
<li><TMPL_IF NAME=ll>*</TMPL_IF><TMPL_VAR NAME=language ESCAPE=HTML></li>
</TMPL_LOOP>
</ul>
</body>
</html>

template_speed_file.tt – Template::Toolkit用のファイル

<html>
<head><title>Programming languages</title></head>
<body>
<h1>[% page_title | html %]</h1>
<br />
<ul>
[% FOREACH language IN languages %]
<li>[% language.language | html %]</li>
[% END %]
</ul>
</body>
</html>

HTMLエスケープあり/なしのスピードについて

tokuhiromさんのコメントにあるように、Text::MicroTemplateは自動でHTMLエスケープがかかる一方、他のテンプレートエンジンでは手動でやる必要があるので、HTMLエスケープを入れて測り直してみました。ちなみに上に載せているベンチの結果は、HTMLエスケープを入れたものになっています。

特筆すべきなのは、HTML::Template::CompiledがキャッシュありかつHTMLエスケープありの場合、HTMLエスケープなしに比べてパフォーマンスがかなり劣化している点です。(その他はちょっとずつパフォーマンスが劣化していますね)。

キャッシュなしかつHTMLエスケープなし

$ perl template_speed_file.pl 3000 0
Benchmark: timing 3000 iterations of HT, HT::Compiled, HT::Pro, MT, TT...
        HT:  4 wallclock secs ( 3.85 usr +  0.10 sys =  3.95 CPU) @ 759.49/s (n=3000)
HT::Compiled: 10 wallclock secs ( 9.99 usr +  0.09 sys = 10.08 CPU) @ 297.62/s (n=3000)
   HT::Pro:  1 wallclock secs ( 0.21 usr +  0.02 sys =  0.23 CPU) @ 13043.48/s (n=3000)
            (warning: too few iterations for a reliable count)
        MT:  2 wallclock secs ( 2.35 usr +  0.05 sys =  2.40 CPU) @ 1250.00/s (n=3000)
        TT:  8 wallclock secs ( 7.83 usr +  0.15 sys =  7.98 CPU) @ 375.94/s (n=3000)
                Rate HT::Compiled          TT          HT          MT    HT::Pro
HT::Compiled   298/s           --        -21%        -61%        -76%       -98%
TT             376/s          26%          --        -51%        -70%       -97%
HT             759/s         155%        102%          --        -39%       -94%
MT            1250/s         320%        233%         65%          --       -90%
HT::Pro      13043/s        4283%       3370%       1617%        943%         --

キャッシュなしかつHTMLエスケープあり

Benchmark: timing 3000 iterations of HT, HT::Compiled, HT::Pro, MT, TT...
        HT:  5 wallclock secs ( 4.60 usr +  0.09 sys =  4.69 CPU) @ 639.66/s (n=3000)
HT::Compiled: 10 wallclock secs (10.56 usr +  0.10 sys = 10.66 CPU) @ 281.43/s (n=3000)
   HT::Pro:  1 wallclock secs ( 0.20 usr +  0.04 sys =  0.24 CPU) @ 12500.00/s (n=3000)
            (warning: too few iterations for a reliable count)
        MT:  2 wallclock secs ( 2.39 usr +  0.07 sys =  2.46 CPU) @ 1219.51/s (n=3000)
        TT: 10 wallclock secs ( 9.65 usr +  0.17 sys =  9.82 CPU) @ 305.50/s (n=3000)
                Rate HT::Compiled          TT          HT          MT    HT::Pro
HT::Compiled   281/s           --         -8%        -56%        -77%       -98%
TT             305/s           9%          --        -52%        -75%       -98%
HT             640/s         127%        109%          --        -48%       -95%
MT            1220/s         333%        299%         91%          --       -90%
HT::Pro      12500/s        4342%       3992%       1854%        925%         --

キャッシュありかつHTMLエスケープなし

$ perl template_speed_file.pl 3000 1
Benchmark: timing 3000 iterations of HT, HT::Compiled, HT::Pro, MT, TT...
        HT:  3 wallclock secs ( 2.50 usr +  0.00 sys =  2.50 CPU) @ 1200.00/s (n=3000)
HT::Compiled:  0 wallclock secs ( 0.15 usr +  0.00 sys =  0.15 CPU) @ 20000.00/s (n=3000)
            (warning: too few iterations for a reliable count)
   HT::Pro:  0 wallclock secs ( 0.10 usr +  0.04 sys =  0.14 CPU) @ 21428.57/s (n=3000)
            (warning: too few iterations for a reliable count)
        MT:  0 wallclock secs ( 0.21 usr +  0.00 sys =  0.21 CPU) @ 14285.71/s (n=3000)
            (warning: too few iterations for a reliable count)
        TT:  1 wallclock secs ( 1.19 usr +  0.01 sys =  1.20 CPU) @ 2500.00/s (n=3000)
                Rate          HT          TT          MT HT::Compiled    HT::Pro
HT            1200/s          --        -52%        -92%         -94%       -94%
TT            2500/s        108%          --        -82%         -87%       -88%
MT           14286/s       1090%        471%          --         -29%       -33%
HT::Compiled 20000/s       1567%        700%         40%           --        -7%
HT::Pro      21429/s       1686%        757%         50%           7%         --

キャッシュありかつHTMLエスケープあり

Benchmark: timing 3000 iterations of HT, HT::Compiled, HT::Pro, MT, TT...
        HT:  3 wallclock secs ( 2.69 usr +  0.00 sys =  2.69 CPU) @ 1115.24/s (n=3000)
HT::Compiled:  0 wallclock secs ( 0.28 usr +  0.00 sys =  0.28 CPU) @ 10714.29/s (n=3000)
            (warning: too few iterations for a reliable count)
   HT::Pro:  0 wallclock secs ( 0.13 usr +  0.02 sys =  0.15 CPU) @ 20000.00/s (n=3000)
            (warning: too few iterations for a reliable count)
        MT:  1 wallclock secs ( 0.22 usr +  0.01 sys =  0.23 CPU) @ 13043.48/s (n=3000)
            (warning: too few iterations for a reliable count)
        TT:  1 wallclock secs ( 1.84 usr +  0.00 sys =  1.84 CPU) @ 1630.43/s (n=3000)
                Rate          HT          TT HT::Compiled          MT    HT::Pro
HT            1115/s          --        -32%         -90%        -91%       -94%
TT            1630/s         46%          --         -85%        -87%       -92%
HT::Compiled 10714/s        861%        557%           --        -18%       -46%
MT           13043/s       1070%        700%          22%          --       -35%
HT::Pro      20000/s       1693%       1127%          87%         53%         --

こちらもあわせてどうぞ


カテゴリー: Perl タグ:
  1. tokuhirom
    2009 年 11 月 15 日 10:34 | #1

    Text::MicroTemplate はデフォルトで自動的に html escape がかかります。ここの部分は速度差として大きくでます。
    他のテンプレートエンジンで | html などとするか、TMT の auto escape をオフにすると、より公平な結果がでるかとおもいます。

  2. 2009 年 11 月 15 日 16:13 | #2

    @tokuhirom さん
    ありがとうございます。Text::MicroTemplate以外でHTMLエスケープの処理を追加してベンチ取り直して、エントリを更新しました。

  1. 2009 年 11 月 15 日 12:52 | #1