2009-12-31

[perl] AnyEvent のファイルハンドル操作

ソケットを扱うとき


TCP/IP のソケットや、Unix ドメインソケットを扱いたいときは、低水準で高速な AnyEvent の IO watcher または、もうちょっと高級な、AnyEvent::Handle を使う。

ローカルファイルを扱うとき

AnyEvent::AIO + IO::AIO を使う。

ローカルファイル (ブロックデバイス) に対しては、AE::io は使えないと AnyEvent の I/O WATCHERSの項 に書いてあります。

2009-12-29

PerlのEncodeモジュールは何を何にエンコードするのか

概要

Perlの文字コード変換用のモジュールEncode.pmの入門用記事は色々ありますが、入門の入門が必要なくらい説明が足りていないと思うので、記事にしてみます。

タイトルの問題の答え

タイトルにした問題の答えは、「夢の国のPerl内部表現文字列を、現実の世界の文字列(バイト列)にエンコードする(変換する)」です。

具体的には、関数$bytes = encode($charset, $string)はPerl内部表現文字列から外に出ていくバイト列を生成する(エンコードする)のに使って、$string = decode($charset, $bytes)は外からバイト列をPerl内部表現にデコードするという感じです。

ご存知かとは思いますが、モジュールの名前はEncodeなのに、なんと逆変換のdecodeもできます。

混乱を誘うさまざまな機能

そして混乱することに、utf8encodingがあります。これらのモジュールはすべて小文字なので、Perlインタプリタの動作を変更するプラグマモジュールであり、ソースコードのエンコーディングを指定するという意味です。

このプラグマを有効にすると、文字列リテラルが単なるバイト列ではなく、Perl内部表現にdecodeされた状態で構文木が作られます。そんな必要がないなら指定してはいけません。

またさらに混乱することに、PerlIOの拡張によって、標準入出力、エラー出力、ファイル入出力で指定可能になる、フィルタの機能を使うと、透過的にエンコード、デコードが起こって何が起こっているのか良く分からなくなるので、encode, decodeを自在に操れるようになってから触るとよいです。

デバッグ方法

Devel::PeekでPerl内部表現文字列かどうかを表すutf8フラグを含めてDumpして観察する。\012みたいなのは1バイトを8進数3桁で表したもの。

2009-12-24

[perl] 今日から始める AnyEvent

AnyEvent とは

これまで、イベントドリブンフレームワークの実装には、POE, Danga::Socket, EV, Event などいろいろあって、互換性もなく混乱した状況でした。

AnyEvent はそういう諸々の API を、データベースへの API で考えられた DBI の様に抽象化したもので、具体的な実装には依存せず、どの(Any)イベントドリブンフレームワークを用いても、同じコードで動きます。今後は AnyEvent で書いておけば安心です。

基本的な考え方

  1. イベントハンドラにコールバック関数を登録します。
    具体的には、on_readみたいなところに関数リファレンスを入れておく。
  2. イベントループを回します。
    具体的には、$cv = AE::cv でcondvarを作って、$cv->recv で処理をブロックしておけばよい。

AnyEvent->condvar がピンとこない

Condition variable? 状態は送信前と送信後の2つあります。ボンバーマンで考えると、リモコンボムです。具体的には、爆発する前の状態と、リモコンを使って爆発させた後の状態の2つです。

送信側は、$cv->send
受信側は、$cv->recv (届くまでブロック) または、$cv->cb($cb) (届いたら$cb->($cv)が実行される)

AE と AnyEvent の違いが良くわからん

AE の方が改良版の高速なAPIです。

AnyEvent->condvar と AE::cv
$w = AnyEvent->timer(after => $after, interval => $interval, cb => $cb) と $w = AE::timer($after, $interval, $cb)
以上の関係を覚えればだいたいOK

hello world

こんな感じでいかがでしょうか。helloが出て、1秒後に world が出ます。

use strict;
use warnings;
use AnyEvent;

my $done = AE::cv;
my $t = AE::timer 1, 0, sub {
    print "world\n";
    $done->send;
};

print "hello\n";

$done->recv;

あとは公式ドキュメントを読む

まずは、AnyEvent::Intro
詳細は、AnyEvent

2009-12-23

りんごジュースと浸透圧について

100%アップルジュースをそのまま飲むとちょっとくどい感じがするので、2倍くらいに薄めて飲むのがちょうどいいと感じていましたが、その根拠についてなんとか計算できたのでメモ。

アップルジュースのパッケージの成分表示を見ると、炭水化物 12.5g / 100mlと書いてあって、りんごに含まれる糖分は果糖やブドウ糖の単糖類。単糖類の分子量は180というのを使うと、100%アップルジュースの糖分のモル濃度は、0.69 mol/L

ところで、生理食塩水(0.9%)の水和性分子のモル濃度を考えると、NaClの式量が58.5というのを使って、完全に電離してイオン2つ分になるとして考えると、0.31 mol/L

よって、アップルジュースも半分位に薄めたらいい感じの浸透圧になりそうな事がわかります。

2009-12-21

moo cards

細長い名刺はmoo MiniCardsで、イギリスからの空便でした。

アドレスは、http://uk.moo.com/en/products/minicards.php クーポンコードを探して入れたらもう少し安くなります。

2009-12-05

[perl] DateTime による日時処理についてのメモ

とても便利なのにまだ十分に活用されていない気がする、DateTime モジュールについて、実際に使ってみて気づいたことを書いておきます。

W3CDTF

DateTime::Format::W3CDTF は小数部を含む秒表現に対応していないので、W3CDTF のスーパーセットである ISO8601形式 に対応した DateTime::Format::ISO8601 を使う。

RSS

RSS の日時表現をパースするときは、表現が何種類かあるので、曖昧さに対応している、DateTime::Format::RSS を使う。

ミリ秒

時間精度が欲しいログを取る際などに、ミリ秒を記録したいときは、DateTime::HiRes を使って、

DateTime::HiRes->now->strftime('%Y-%m-%d %H:%M:%S.%3N')

という感じで出力する。%3N がミリ秒の部分となる。

JavaScript などで欲しくなる、ミリ秒でのUNIX epochが必要なときは、

DateTime::HiRes->now->strftime('%s%3N')

とする。

デバッグ

変な感じのときは、Data::Dumper で、内部変数を見てみる。