Apache モジュールで ClearSilver を使う(各種言語のテンプレートエンジンベンチマーク)


ClearSilverを使ってみる - spiritlooseのはてなダイアリー に引き続き ClearSilver を使ってみる。


ClearSilver の使いどころは、Cで書いたCGIで使うケースなどが一般的だとおもうけど、ここではApacheモジュール(Apache2)で使ってみる。

(CGIはライブラリがついてくるみたいだけど、よく見てない)

というわけで、簡単なサンプルを作ってみた。


まず

/usr/local/apache2/bin/apxs -g -n hello

Apacheモジュールの雛形を作る。

でmod_hello.cを編集。

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
#include "ClearSilver.h"

static NEOERR *render_cb(void *obj, char *s)
{
    request_rec *r = (request_rec *)obj;
    ap_rputs(s, r);
    return STATUS_OK;
}

static void output_body(request_rec *r)
{
    HDF *hdf;
    CSPARSE *cs;
    hdf_init(&hdf);
    hdf_set_value(hdf, "message", "hello world!");
    cs_init(&cs, hdf);
    cs_parse_file(cs, "/path/to/hello.cs");
    cs_render(cs, r, render_cb);
    cs_destroy(&cs);
    hdf_destroy(&hdf);
}

static int hello_handler(request_rec *r)
{
    if (strcmp(r->handler, "hello")) {
        return DECLINED;
    }
    r->content_type = "text/html";
    if (!r->header_only) {
        output_body(r);
    }
    return OK;
}

static void hello_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(hello_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA hello_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    hello_register_hooks   /* register hooks                      */
};

hello.cs

<html>
<head>
<title>hello world!</title>
</head>
<body>
<h1><?cs var:message ?></h1>
</body>
</html>

ClearSilverのライブラリを使うようにMakefile を編集する。

以下は編集する部分だけ。

APXS=/usr/local/apache2/bin/apxs
APACHECTL=/usr/local/apache2/bin/apachectl

INCLUDES=-I/usr/local/include/ClearSilver
LIBS=-lneo_cs -lneo_cgi -lneo_utl -lz

all:
	$(APXS) -c $(INCLUDES) $(LIBS) -Wl,-g mod_hello.c

よくわからなかったので、all の部分はかなり直接書いてしまっている。


これで make && make install でOK。


後は httpd.conf に

LoadModule hello_module modules/mod_hello.so
<Location /hello>
    SetHandler hello
</Location>

と書いて再起動すれば /hello にアクセスしたときに /path/to/hello.cs の内容が表示される。


いい機会なのでベンチを取ってみる。


比較対照としてCGIでは差がつきすぎるので、mod_perl(ver.1) のHandlerと比較してみた。


Perl のコードは適当に

package Hello;
use strict;
use warnings;

use Apache::Constants qw(:common);
use Template;

sub handler ($$) {
    my ($class, $r) = @_;
    my $tt = Template->new(
        INCLUDE_PATH => '/path/to/tmpldir',
    );
    my $param = { message => 'hello world!' };
    $tt->process('hello.tt', $param, \my $output)
        or return DECLINED;
    $r->content_type('text/html');
    $r->print($output);
    return OK;
}
1;

テンプレートはほぼ同じなので省略。


一応、ほぼ同じコードのCGIも用意してみた。

hello.cgi

#!/usr/local/bin/perl
use strict;
use warnings;

use CGI;
use Template;

my $q = CGI->new;
my $tt = Template->new(INCLUDE_PATH => '/path/to/tmpldir');
my $param = { message => 'hello world!' };
$tt->process('hello.tt', $param, \my $output)
    or die $tt->error;
print $q->header;
print $output;

おまけで PHP4 + Smarty

hello.php

<?php
require_once('Smarty/Smarty.class.php');
$smarty = new Smarty;
$smarty->assign('message', 'hello world!');
$smarty->display('index.tpl');
?>

で ab -n 100 -c 10 の結果は以下(環境はcoLinux)。

言語 テンプレートエンジン Requests per second
C (Apache2 module) ClearSilver 518.00
Perl(mod_perl Handler) Template-Toolkit 170.58
PHP4(mod_php4) Smarty 99.53
Perl(CGI) Template-Toolkit 2.61


CGIは論外として、さすがにApacheモジュールは速い。mod_perl も相当速いけど。


パフォーマンスが要求される部分でこのような形で使用するのはありだと思った。


DB見たり書いたり、メンテナンスが頻繁な箇所では正直Cで書くのはしんどいけど、ほぼ静的なページとかで使い道はかなりありそう。

デザイン変更はテンプレートを編集すればいいので、見た目の変更は楽だし。


ドキュメントを見ると、マクロとかも定義できたりと、結構強力。


というわけで結構お勧め。