まだ重たいCMSをお使いですか?
毎秒1000リクエスト を捌く超高速CMS「adiary

2006/07/28(金)map関数の使い方

perl の map 関数の使い方

map関数の説明は他を参照してもらうとして。

$categories->[n] = { cat_ID  => カテゴリID, cat_name => カテゴリ名 };
$post2cat->[n]   = { post_id => 記事ID,  category_id => カテゴリID };

という2つのハッシュリファレンスからなる配列があったとき、記事ID→カテゴリ名という変換テーブル(ハッシュ)を作る方法。

my %cat2name  = map { $_->{cat_ID}  => $_->{cat_name} } @categories;
my %post2name =	map { $_->{post_id} => $cat2name{ $_->{category_id} } } @post2cat;

とすると、$post2name{記事ID} → カテゴリ名となります。でもこの場合、@post2cat の最後に出た要素が優先されるので、最初に出た要素を優先するために、

map { $post2name{ $_->{post_id} } ||= $cat2name{ $_->{category_id} } } @post2cat;

と書けます。

foreach(@ary) で回してるものは、mapに置き換えた方がスマートかつ効率的かも知れもません。

grep

grepは別に正規表現なだけではなく、格納条件を指定することもできるらしい。

my @newary = grep { $_ > 100 } @ary;

my @newary;
foreach(@ary) {
	if ($_ > 100) { push(@newary, @ary); }
}

と等価らしい。grep コマンドの印象が強かったから全然気づかなかった。

追記

んー便利だ。今まで foreach(@ary) で書いてたところが、いくつも書き直せそうだけど……まぁいいや。*1

とりあえず、まだ知らないことがありそうなのでPerl5の関数リストでも眺めておこう。

*1 : ハッカーのために可読性優先で書いてる部分もあったりするので。

2006/07/28(金)7/28版ToDo

この前の7/7版ToDoが古くなったので書き直してみるのココロ。たまには書式を変えてはてなの「あしか」式に(笑

終わった

  • Google Analytics
  • 日記再構築機能
  • 標準の画像アップロード機能
  • 書き込み日時の管理仕様(初公開日=書き込み日時)
  • mixiの日記ログ、インポート
  • adiaryからadiaryへ引っ越した際に、記事key指定によるリンクがずれない仕組み
  • Apache1.3やAnHttpdやLighttpdなど、動作テストしてなかった環境への対応

などなど。

すぐやる

すぐというか正式リリースまでには。

  • 画面デザイン編集機能
  • 月別リスト。ページトップに月別リスト(tDiary/はてな方式)の機能
  • 複数のRSS出力 (idea by serika)

実装完了

  • 【β8】記法タグの入れ子
  • 【β10】カテゴリの実装の修正(カテゴリ編集画面改良、親カテゴリ指定エクスポートなど)
  • 【β11】pod casting対応
  • 【β12】ページ送り、日記検索
  • 【β13】新着コメント/TBの瞬時表示

そのうちやる

  • デザイン
    • ユーザーテーマ(指定した日記を好きなテーマで見られるように→cookie使用)
    • テーマ選択機能/管理の改良
  • 広告
    • Amazonのおすすめ(Amazonライブリンク/アカウント取らないと試せない&実装できない……)
    • Google ADS機能(上に同じ)
  • 機能拡張
    • 機能拡張の仕様を具体的に詰める(現状も拡張自体はできるのだけども)
  • テーマ作成用サンプルHTMLと情報の提供
  • ドキュメント整備
  • モバイル機能
    • メールからの更新機能
    • 新着コメント/TBのメール通知機能
    • モバイル向けテンプレート(誰か作らないかなぁ)
  • 技術面
    • スケルトンコンパイラのさらなる高速化(forexec)(済:β10)
    • ページ出力のキャッシュ機構(半静的生成も視野に)

ペンディング(保留)

  • tDiary互換テンプレート(スケルトン)

adiaryへの要望/バグ報告などは

この記事にコメント or トラックバックでお願いします。

2006/07/27(木)mixi export

mixi exportを公開しました。

mixiの日記およびコメントのログを取得し、はてなダイアリーやadiaryで取り込める形式に変換する(エクスポートする)ツールです。エクスポート結果を adiary に一度取り込むことで、Movable Type形式やJUGEM形式などで出力することも可能になります。

backup_mixiのあるディレクトリに置いた場合は、自分でログを取得せず、backup mixiの取得済ログを変換します*1。詳細は付属のマニュアルを参照ください。

このツールに関する突っ込み、要望などはこの記事へお願いします。

*1 : backup_mixiにも変換機能はありますが、コメントが出力されないのと本文の<br>除去が微妙なので……

2006/07/26(水)FileHandle vs Symbol

perl でオブジェクト指向を目指し、use strictしたプログラムを徹底していくと、どうにかしたくなるのが「ファイルハンドル」の存在です。

open(FD, "test.txt");
close(FD);

この FD をオブジェクトとして使い関数に対して引数として与えたりしたいのですが、use strict な環境では

my $fh = 'FD';
open($fh, "test.txt");
close($fh);

とやっても、エラーになってしまいます。かと言ってこのためだけに no strict refs; ともしたくない。またこの方法では、Perlをマルチスレッド動作させるとき、ファイルディスクリプタの名前空間が衝突し、ファイルが開けなくなる問題もあります。

ネットで情報を漁っていると、こういうときはファイルハンドルを動的生成する方法が紹介されています。

use FileHandle ();
my $fh = FileHandle->new();
open($fh, "test.txt");
close($fh);
use IO::File ();
my $fh = IO::File->new();
open($fh, "test.txt");
close($fh);

いずれの方法も実際うまく動きますし、動作上はなんの問題もありません。ただ、これらのモジュールはファイルハンドルを生成するためだけに使うにはリッチすぎます。つまり機能的すぎてモジュールのロードが遅いということです。*1

たた単純に、ファイルハンドルを動的生成したい場合は、

use Symbol ();
my $fh = Symbol::gensym();
open($fh, "test.txt");
close($fh);

とするのがベストだと思われます。

どれくらい速度が違うか、それぞれのサンプルだけのプログラムを作成し実行し、time コマンドで計測してみましたので参考までに。

実現方法実行速度
FileHandle100ms
IO::File94ms
Symbol23ms
直接指定14ms

こういう計測の結果、adiary では Symbol モジュールを使っています。

*1 : 逆に言えば、Socket通信のハンドルを作り、出力を自動的にフラッシュしたいときなどは FileHandle や IO::File モジュールを用いて $fh->autoflash(1) などとするのがベターです。

Perl 5.6.0以降限定、もっとよい方法

Perl 5.6.0からの新機能として、ファイルハンドルを自動で生成する機能があります

ハンドラを使用する関数 (open(), opendir(), pipe(), socketpair(), sysopen(), socket(), accept()) では、ファイルハンドルとして未定義のスカラ変数が与えられたとき、ファイルやディレクトリのハンドルを自動的に生成し変数に設定します。

と書かれています(意訳)。つまりどういうことかというと、上と同等のことをやるためには、

open(my $fh, "test.txt");
close($fh);

と書けば十分だということになります。こうすれば Symbol モジュールのロードは必要なくなり、メモリや実行時間の節約になります。ただし、これが実行できるのは5.6.0以降ですので、ソースの最初に

use 5.6.0;

と書いておくべきでしょう。adiaryでは現在(β7以降)この方法を使用しています。

2006/07/25(火)7/25版スナップショット

βリリースではなくスナップショットです。落としたい人は、ダウンロードページを参照ください。

  • mod_perl等の環境で、メモリリークする問題を修正しました。mod_perl環境の場合のみ、すでにリークしたメモリを開放するためApacheの再起動が必要です。
  • AnHttpd, lighttpd, Apache 1.3.x (cgiとmod_perl/1.29*1) などでの動作テストと、Apache1.3 などの環境でパス自動解析に失敗する不具合を修正を行いました。*2
  • ファイルアップローダーのコンパイルログが標準でonになっていたので修正しました。
  • スケルトンの更新チェックをより厳格にしました。
  • ssh で port forward した環境などで、redirect がうまく動作してなかったので対応しました。

メモリリークの関係で、データベースハンドラを解放できず、ここのレンタルサービスが何度か停止しご迷惑をおかけしました。今は修正されています。

*1 : mod_perl1.xxでの運用はあまり推奨しません

*2 : 主にApache 2.xのみテストされていますので、他のサーバシステムで問題を発見した場合はぜひともご連絡ください。