perlのテンプレートエンジンは TT(template-toolkit が有名です。
他にも HTML::Template や Mason などがメジャーどころとしては存在するかと思います。
弊社では通常は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=]
と記述が変わるあたりが不便といえば不便でしょうか。
しかしそれにしても中々のスピードですね・・・
記述方法や応用例などをもう少し調査したいと思います。