酒日記

Wed, 04 Sep 2002

秋味 (6% × 1000 ml)

Template-Toolkit 続き。

Template-Toolkit をいじっていて、なんだか動作がもっさりしているような気がしたのでベンチマークを取ってみる。

ベンチマークスクリプトは

#!/usr/bin/perl

use Benchmark;
use HTML::Template;
use Template;
use strict;

my $prefix = $ARGV[0];

my %vars = (
    test_val  => join('', (0..9, "a".."z", "A".."Z")),
    test_loop => [
        { val => 1 },
        { val => qq|酒日記| },
        { val => "http://sake-nikki.dyndns.org/cgi-bin/index.cgi?rm=hogehoge" },
    ],
    test_if   => (rand > 0.5) ? 1 : 0,
);

sub test_tt
{
    my $tt = Template->new({
        INCLUDE_PATH => "./",
    });
    my $output;
    $tt->process($prefix. "test.tt", \%vars, \$output)
        or die $tt->error;
}

sub test_tp
{
    my $tp = HTML::Template->new(
        filename          => $prefix. "test.tp",
        global_vars       => 1,
        die_on_bad_params => 0,
    );
    my $output;
    $tp->param(%vars);
    $output = $tp->output;
}

timethese(100, {
    'HTML::Template  ' => \&test_tp,
    'Template-Toolkit' => \&test_tt,
});

こんな感じ。テンプレートは test.tt (Template-Toolkit用) が

test_val=[% test_val %]
[% FOREACH l = test_loop %]
    val=[% l.val %]
    val_html=[% l.val | html %]
[% END %]
[% IF test_if %]true[% ELSE %]false[% END %]

で、test.tp (HTML::Template) は、

test_val=<TMPL_VAR name="test_val">
<TMPL_LOOP name="test_loop">
    val=<TMPL_VAR name="val">
    val_html=<TMPL_VAR name="val" escape="html">
</TMPL_LOOP>
<TMPL_IF name="test_if">true<TMPL_ELSE>false</TMPL_IF>

これ。動作としては同等品。更に

  • test.tt, test.tp を10個連結した large_test.t[tp]
  • test.tt, test.tp を100個連結した huge_test.t[tp]
  • test.t[tp] とHTML文書(酒日記を適当に抜粋して 1600 byteほどにしたもの) を、3個づつ連結した real_test.t[tp]

を用意。

...

ベンチマーク結果

test.t[tp]
HTML::Template  :  0 wallclock secs ( 0.42 usr +  0.01 sys =  0.43 CPU) @ 232.56/s (n=100)
Template-Toolkit:  2 wallclock secs ( 1.83 usr +  0.02 sys =  1.85 CPU) @ 54.05/s (n=100)

large_test.t[tp]
HTML::Template  :  4 wallclock secs ( 4.74 usr +  0.01 sys =  4.75 CPU) @ 21.05/s (n=100)
Template-Toolkit: 12 wallclock secs (11.85 usr +  0.08 sys = 11.93 CPU) @  8.38/s (n=100)

real_test.t[tp]
HTML::Template  :  1 wallclock secs ( 1.75 usr +  0.03 sys =  1.78 CPU) @ 56.18/s (n=100)
Template-Toolkit:  5 wallclock secs ( 4.40 usr +  0.05 sys =  4.45 CPU) @ 22.47/s (n=100)

huge_test.t[tp]
HTML::Template  : 267 wallclock secs (266.37 usr +  0.08 sys = 266.45 CPU) @  0.38/s (n=100)
Template-Toolkit: 139 wallclock secs (138.85 usr +  0.27 sys = 139.12 CPU) @  0.72/s (n=100)

huge では Templat-Toolkit が HTML::Template を上まわるものの、それ以外では惨敗。 HTML::Template の圧勝。

両者ともに、一旦コンパイルしたテンプレートをキャッシュすることで高速化ができる (特に mod_perl 環境で有効) ので、キャッシュを有効にして再度ベンチマークを取ってみる。 具体的には、

 my $tt = Template->new({
     INCLUDE_PATH => "./",
+    COMPILE_DIR  => "/var/tmp/tt/",
+    COMPILE_EXT  => ".ttc",
 });

 my $tp = HTML::Template->new(
     filename          => $prefix. "test.tp",
     global_vars       => 1,
     die_on_bad_params => 0,
+    cache             => 1,
 );

としてキャッシュを有効にする。結果は以下。

test.t[tp]
HTML::Template  :  0 wallclock secs ( 0.24 usr +  0.00 sys =  0.24 CPU) @ 416.67/s (n=100)
Template-Toolkit:  0 wallclock secs ( 0.71 usr +  0.02 sys =  0.73 CPU) @ 136.99/s (n=100)

large_test.t[tp]
HTML::Template  :  3 wallclock secs ( 3.67 usr +  0.00 sys =  3.67 CPU) @ 27.25/s (n=100)
Template-Toolkit:  3 wallclock secs ( 2.94 usr +  0.03 sys =  2.97 CPU) @ 33.67/s (n=100)

real_test.t[tp]
HTML::Template  :  0 wallclock secs ( 0.65 usr +  0.01 sys =  0.66 CPU) @ 151.52/s (n=100)
Template-Toolkit:  2 wallclock secs ( 1.30 usr +  0.02 sys =  1.32 CPU) @ 75.76/s (n=100)

huge_test.t[tp]
HTML::Template  : 274 wallclock secs (274.28 usr +  0.01 sys = 274.29 CPU) @  0.36/s (n=100)
Template-Toolkit: 35 wallclock secs (33.95 usr +  0.24 sys = 34.19 CPU) @  2.92/s (n=100)

簡単にまとめると、

  • 単純な(小さい)テンプレートでは、HTML::Template が速い
  • Template-Toolkit は、キャッシュによる速度向上が大きい
  • テンプレート上での展開要素が多い場合、Template-Toolkit が有利 (テンプレートが巨大になってもパフォーマンスが落ちにくい)
  • 実運用環境では、ほぼ互角

というところでしょうか。HTML::Template のほうがシンプルな分、速度的には有利な感じ。 Template-Toolkit が明らかに高速だった huge_ は、実際の Web アプリケーションではまずありえない (特殊な) テンプレートだし。


Tue, 03 Sep 2002

甕幻 (25% × 250 ml)

長い間、PHP でページ生成 → wget で静的ファイルに落とす → 自作FTPクライアントでサーバに PUT、 という流れで酒日記を更新していたのだが。 やっと重い腰を上げて、PHP でページ生成している部分を Perl の CGI::Application + Template-Toolkit で実装しなおし。

昨日からぼちぼち進めて、ほぼ完了。

今回、いつも使っている HTML::Template ではなくて Template-Toolkit を使ってみたのだが、

<select>
[% FOREACH per = per_loop %]
<option value="[% per %]"[% IF per == article.per %] selected[% END %]>[% per %]</option>
[% END %]
</select>

こんなふうに、テンプレート側で条件分岐の条件を設定できたり、

<h3>換算酒量</h3>
<table>
[% USE autoformat(form => '>>>>>.<<', numeric => 'AllPlaces') %]
<tr><td>エタノール換算</td><td><b>[% x = s.total_alc_sum / 1000; autoformat(x) %]</b> ([% x = x / s.days; autoformat(x) %] /day)</td></tr>

簡単な演算やフォーマットの設定ができたりで、非常に便利。 ただ、強力さにまかせてロジック (MVC モデルでいうところの M と C の部分) に絡むところをいじりだすと、 ヘタに作った PHP のようにメンテ不能に陥りそうだけど。
# ちゃんとルールを作って運用、制作しなくては。


Tue, 25 Jun 2002

一番絞り 樽生 (5.5% × 900 ml)

仕事のからみで、XML と RDB を適当に (適切に) 組み合わせて扱う必要に迫られたので、実験など。

XML を Perl のモジュールっぽく扱うには、XML::DOM のラッパーとして実装されている XML::EasyOBJ を使って、XML::EasyOBJ のオブジェクトを Template-Toolkit に放り込んでみるといい感じ。

たとえば、扱う XML が

<thread>
    <article>
        <no>1</no>
        <title>そうですね</title>
        <message>どうしたものでしょうかね</message>
        <author>ふじわら</author>
    </article>
    <article>
        <no>2</no>
        <title>Re: そうですね</title>
        <message>まあ、ぼちぼち。</message>
        <author>ふじさん</author>
    </article>
</thread>

のような構造だった場合 (掲示板を XML で表現したような場合ね)。 この XML から XML::EasyOBJ のオブジェクトを生成して Template に突っ込めば、

<dl>
[% FOREACH article = thread.article %]
<dt>[% article.no.getString %] : [% article.title.getString %]</dt>
<dd>[% article.message.getString %]<br>
    by [% article.author.getString %]
</dd>
[% END %]
</dl>

てなテンプレートを書くことで、

1 : そうですね
どうしたものでしょうかね
by ふじわら
2 : Re: そうですね
まあ、ぼちぼち。
by ふじさん

というふうに展開できる。

今まで好んで使っていた HTML::Template と比較すると、「オブジェクトを突っ込めばいい」 (そうすれば良きに計らってくれる) という点が魅力的。かつ危険な香り。

HTML::Template は (多分かなり意識的に) テンプレート側に機能を持たさないように実装されているのだが、その気持ちはよく分かる。 テンプレートでいろいろできちゃうと便利なのだが、しかし、無節操にやってしまうとメンテ不能に陥るからねえ。
# かつて PHP でそれをやってしまって、今も面倒を見るのに苦労していることもあり。


powered by blosxom