Text::MicroTemplate と Template-Toolkit のベンチマーク

Perlの軽量フレームワークMENTANanoA)から生まれた Text::MicroTemplateと、ご存じ Template-Toolkit の比較のため、ベンチマークしてみました。参考までに、こちらも有名どころの HTML::Template も入れてみました。

結果

Benchmark: timing 5000 iterations of HTML::Template, Template-Toolkit, Text::MicroTemplate...
HTML::Template:  2 wallclock secs ( 1.68 usr +  0.04 sys =  1.72 CPU) @ 2906.98/s (n=5000)
Template-Toolkit:  9 wallclock secs ( 8.73 usr +  0.36 sys =  9.09 CPU) @ 550.06/s (n=5000)
Text::MicroTemplate: 10 wallclock secs ( 8.83 usr +  0.44 sys =  9.27 CPU) @ 539.37/s (n=5000)
                      Rate Text::MicroTemplate Template-Toolkit   HTML::Template
Text::MicroTemplate  539/s                  --              -2%             -81%
Template-Toolkit     550/s                  2%               --             -81%
HTML::Template      2907/s                439%             428%               --

Mac OS X 10.5、Perl 5.8.8 にて。実際の使用にあわせて、キャッシュ有り、UTF-8フラグを立てる仕様で、単純なテンプレート処理を計っています(コードは下記)。ちなみに、Text::MicroTemplate Ver 0.05、Template-Toolkit Ver 2.21、HTML::Template Ver 2.9 を使用。

HTML::Template は低機能なだけあって速いですね。Text::MicroTemplate と Template-Toolkit は、いずれもPerlで実行できるソースコードを作り出してからそれを eval する仕組みなので、eval のコストがほとんどになってしまうようです。

それじゃあキャッシュさせなかったらどうよ、というベンチマークの結果は以下。キャッシュさせないように、テンプレートの内容を予め読み込んでおいて scalar_ref で渡すようにしています。

Benchmark: timing 5000 iterations of HTML::Template, Template-Toolkit, Text::MicroTemplate...
HTML::Template:  5 wallclock secs ( 5.34 usr +  0.01 sys =  5.35 CPU) @ 934.58/s (n=5000)
Template-Toolkit: 19 wallclock secs (19.17 usr +  0.05 sys = 19.22 CPU) @ 260.15/s (n=5000)
Text::MicroTemplate:  9 wallclock secs ( 9.06 usr +  0.04 sys =  9.10 CPU) @ 549.45/s (n=5000)
                     Rate Template-Toolkit Text::MicroTemplate    HTML::Template
Template-Toolkit    260/s               --                -53%              -72%
Text::MicroTemplate 549/s             111%                  --              -41%
HTML::Template      935/s             259%                 70%                --

最近の軽量フレームワーク

私の仕事としては、Perlモジュールが自由にインストールできない、ホスティングだったり管理者がうるさい自社サーバで使うものが多いので、最近の軽量フレームワークMojoなどはとてもありがたい存在です。ソースコードを読んで自分の業務にあった軽量フレームワークを作ったりして勉強しています。

Mojo::Template は今回の比較には入れませんでしたが、Text::MicroTemplate はこれをベースにしているので、同じような結果がでるのではないか、と思っています。

PHPでは、同じような理由で CakePHP を使ったりもしています。

こういったニーズって結構あるんじゃないかなぁと思っているのですが、Perlではなかなかメジャーな、PurePerl(コアモジュール含む)なフレームワークって無かったですよね。今回ベンチマークしたモジュールは、全て「.pm」ファイルを置くだけで実行できるPurePerlなテンプレートエンジンです。MENTANanoA の作者の方々に感謝しつつ、もっとこの流れが発展することを願っております。

ベンチマークのソース

use strict;
use warnings;
use utf8;
use Encode;
use Benchmark qw( timethese cmpthese );

use Text::MicroTemplate::File;
use Template;
use Template::Provider::Encoding;
use Template::Stash::ForceUTF8;
use HTML::Template;

my $times = shift @ARGV || 1000;

my $data = {
  items => [
    {
      id   => 'aaa',
      name => 'あいうえおかきくけこ',
      desc => '説明文1です。説明文1です。',
      stat => 0,
    },
    {
      id   => 'bbb',
      name => 'さしすせそたちつてと',
      desc => '説明文2です。説明文2です。',
      stat => 1,
    },
    {
      id   => 'ccc',
      name => 'なにぬねのはひふへほ',
      desc => '説明文3です。説明文3です。',
      stat => 0,
    },
  ],
  doc_root => '/path/to/document_root/',
};

my $tmpl_tt = './tmpl_tt.html';
my $tmpl_mt = './tmpl_mt.html';
my $tmpl_ht = './tmpl_ht.html';

binmode STDOUT, ':utf8';

my $comp = timethese( $times, {
  'Template-Toolkit'    => \&template_toolkit,
  'Text::MicroTemplate' => \&text_microtemplate,
  'HTML::Template'      => \&html_template,
} );

cmpthese( $comp );

sub template_toolkit {
  my $tmpl = Template->new(
    LOAD_TEMPLATES => [ Template::Provider::Encoding->new(
      RELATIVE => 1,
      COMPILE_DIR    => './cache_tt',
    ) ],
    STASH          => Template::Stash::ForceUTF8->new(),
  );
  my $html = '';
  $tmpl->process( $tmpl_tt, $data, \$html ) or die $tmpl->error();
  return $html;
}

sub text_microtemplate {
  my $tmpl = Text::MicroTemplate::File->new(
    cache => 1,
  );
  my $html = $tmpl->render_file( $tmpl_mt, $data );
  return ${$html};
}

sub html_template {
  my $tmpl = HTML::Template->new(
    filename => $tmpl_ht,
    die_on_bad_params => 0,
    cache => 1,
    filter => sub {
      my $text_ref = shift;
      ${$text_ref} = Encode::decode( 'utf8', ${$text_ref} );
    }
  );
  $tmpl->param( %{$data} );
  return $tmpl->output();
}

そうそう、Template-Toolkit の UTF-8 フラグ立てには、Template::Provider::Encodingを使っています。