[perl] TTより5倍速い?テンプレートエンジン"Tenjin"を試す

2009年5 月24日  |  Written by matsumoto  |  under Perl Yahoo!ブックマークに登録    はてなブックマーク - [perl] TTより5倍速い?テンプレートエンジン"Tenjin"を試す

perlのテンプレートエンジンは TT(template-toolkit が有名です。
他にも HTML::TemplateMason などがメジャーどころとしては存在するかと思います。

弊社では通常はTTを利用していますが、今回はそれとは別のテンプレートエンジン tenjin を試してみます。

2009.07.28
CPANにUPされたみたいです。下記インストール方法ではなく

cpan > install Tenjin

でインストールした方が良いです

Tenjinについて

Tenjinは kuwata-lab.com 様で作成されている テンプレートエンジンです、perl/PHP/ruby他、JSなども対応しています。

PHPやJSPのようにHTML内にスクリプトを埋め込むスタイルで、レンダリングの高速性を特徴としています。

  • Tenjin is a very fast and full-featured template engine available in several script languages.

    • Tenjinはとても高速で、各種言語でフル機能を実装したテンプレートエンジンです
  • 3 times faster than Smarty.
    • Smarty (PHPのテンプレートエンジン)より3倍速いです
  • 5 times faster than Template-Toolkit.

との事なので 非常に興味が沸きます。TTより5倍も速くなるのでしょうか?!

ダウンロード・インストール

perlのバージョンを確認

今回は CentOS5.3 にPerl 5.8.8 が入っている状態を想定します。perlが無い場合・perlのバージョンが低い場合は

# yum update perl

で最新版に更新できます。

Tenjin をダウンロード

ダウンロードサイト(sourceforge) から perl版のTenjin(pltenjin) をダウンロードします。
現在の最新版は 0.0.2 ですので、こちらをダウンロードします

# cd /usr/local/src
# wget http://ncu.dl.sourceforge.net/sourceforge/tenjin/pltenjin-0.0.2.tar.gz

インストール

解凍し、中にある lib/Tenjin.pm と bin/pltenjin をコピーします。
今回は Tenjin.pmはperlのライブラリのディレクトリに、 pltenjinは /usr/local/bin 以下にコピーしました。

# tar xvzf pltenjin-0.0.2.tar.gz
# cd pltenjin-0.0.2
# cp lib/Tenjin.pm /usr/lib/perl5/site_perl/5.8.8/Tenjin.pm
# cp bin/pltenjin /usr/local/bin/pltenjin

この辺りはインストーラーがあると作業がシンプルになるかもしれないですね。

ベンチマーク

では、実際に同じようなテンプレートでTTと速度を比べてみます。
ベンチマークを行うソースは以下です。

bentch.pl

#!/usr/bin/perl
use strict;

use utf8;
use Benchmark qw/timethese cmpthese/;
use Template;
use Template::Stash::ForceUTF8;
use Template::Provider::Encoding;
use Tenjin;
use Encode;

my $title = 'テンプレートエンジン・ベンチマーク測定';
my $entries = [
    { name => 'ヤフージャパン',   url => 'http://www.yahoo.co.jp/' },
    { name => 'ライブドア', url => 'http://www.livedoor.com/' },
    { name => 'ミクシィ',     url => 'http://mixi.jp/' },
    { name => 'はてな',   url => 'http://www.hatena.ne.jp' },
    { name => 'Goo',      url => 'http://www.goo.ne.jp' },
    { name => 'google',   url => 'http://www.google.co.jp/' },
    { name => 'youtube', url => 'http://www.youtube.com/' },
    { name => 'ニコニコ動画',     url => 'http://www.nicovideo.jp/' },
    { name => 'flickr',   url => 'http://www.flickr.com/' },
    { name => 'Delicious',      url => 'http://delicious.com/' },
];

my $bench = timethese(1000, {
    'TT' => sub {
        my $tt = Template->new({
            LOAD_TEMPLATES   => [ Template::Provider::Encoding->new({
                DEFAULT_ENCODING => 'utf-8',
                ABSOLUTE => 1,
                RELATIVE => 1,
                TRIM => 1,
            }) ],
            STASH => Template::Stash::ForceUTF8->new,
        });
        $tt->process('bench.tt', { title => $title, entries => $entries }, my $out);
    },
    'TT(Compiled)' => sub {
        my $tt = Template->new({
            LOAD_TEMPLATES   => [ Template::Provider::Encoding->new({
                DEFAULT_ENCODING => 'utf-8',
                ABSOLUTE => 1,
                RELATIVE => 1,
                TRIM => 1,
                COMPILE_EXT => '.ttc',
                COMPILE_DIR => './ttc',
            }) ],
            STASH => Template::Stash::ForceUTF8->new,
        });
        $tt->process('bench.tt', { title => $title, entries => $entries }, my $out);
    },
    'Tenjin(Compiled)' => sub {
        my $engine = new Tenjin::Engine();
        my $out = $engine->render('bench.plhtml', { title => $title, entries => $entries });
        $out = encode("utf8", $out);
    }
});
cmpthese($bench);

テンプレートは以下です

bench.tt (TT用)

[% title | html %]

<ul>
[% FOREACH e IN entries %]
<li><a href="[% e.url %]">[% e.name | html %]</a></li>
[% END # FOREACH %]
</ul>

<ul>
[% FOREACH e IN entries %]
<li><a href="[% e.url %]">[% e.name | html %]</a></li>
[% END # FOREACH %]
</ul>

<ul>
[% FOREACH e IN entries %]
<li><a href="[% e.url %]">[% e.name | html %]</a></li>
[% END # FOREACH %]
</ul>

[% title | html %]

bench.plhtml (Tenjin用)

[=$title=]

<ul>
<?pl foreach my $e (@$entries) { ?>
 <li><a href="[==$e->{url}=]">[=$e->{name}=]</a></li>
<?pl } ?>
</ul>

<ul>
<?pl foreach my $e (@$entries) { ?>
 <li><a href="[==$e->{url}=]">[=$e->{name}=]</a></li>
<?pl } ?>
</ul>

<ul>
<?pl foreach my $e (@$entries) { ?>
 <li><a href="[==$e->{url}=]">[=$e->{name}=]</a></li>
<?pl } ?>
</ul>

[=$title=]

ベンチマーク結果

上記スクリプトを実行した結果です。TTのオーバーヘッドはやはり大きいのでしょうか、シンプルな反復処理だけですが、
相当な違いが結果として出ています。

./bench.pl
Benchmark: timing 1000 iterations of TT, TT(Compiled), Tenjin(Compiled)...
        TT:  9 wallclock secs ( 9.10 usr +  0.02 sys =  9.12 CPU) @ 109.65/s (n=1000)
TT(Compiled):  5 wallclock secs ( 4.15 usr +  0.08 sys =  4.23 CPU) @ 236.41/s (n=1000)
Tenjin(Compiled):  0 wallclock secs ( 0.61 usr +  0.01 sys =  0.62 CPU) @ 1612.90/s (n=1000)
                   Rate               TT     TT(Compiled) Tenjin(Compiled)
TT                110/s               --             -54%             -93%
TT(Compiled)      236/s             116%               --             -85%
Tenjin(Compiled) 1613/s            1371%             582%               --

ちょっと極端な例かもしれませんが、Tenjinの速度は
通常のTTと比べて13倍以上、TTコンパイル版と比べても5倍以上のスピードが出ています。

Rate TT TT(Compiled) Tenjin(Compiled)
TT 110/s -53% -94%
TT(Compiled) 236/s 115% -86%
Tenjin(Compiled) 1613/s 1371% 582%

ただ、TTが便利な点も多く、
ハッシュとオブジェクトの区別や、ループ処理時はloopオブジェクトが自動生成されるなど
非常に運用しやすい形態になっています。

例えば
TTでは以下は同じ文法かと思います。

[% hash.key %]
[% object.method %]

しかしTenjinでは素のPerlコードをそのまま書くため、

[=$hash->{'key'}=]
[=$object->method=]

と記述が変わるあたりが不便といえば不便でしょうか。

しかしそれにしても中々のスピードですね・・・

記述方法や応用例などをもう少し調査したいと思います。

現在コメントはありません | コメントの投稿はこちら

コメントを書き込む

コメント本文

※コメントのフォーム内で以下のタグがご利用いただけます
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

私はチーム・マイナス6%です