お知らせ
▼ 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 コマンドで計測してみましたので参考までに。
| 実現方法 | 実行速度 |
|---|---|
| FileHandle | 100ms |
| IO::File | 94ms |
| Symbol | 23ms |
| 直接指定 | 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以降)この方法を使用しています。
- TB-URL http://adiary.blog.abk.nu/074/tb/
-
▼
Perlと標準入出力ファイルハンドル
adiary開発日誌 Perlで「use strict」で使用している場合、ファイルハンドルを動的に生成し変数に代入するには一工夫する必要がありました。 さらに、このファイルハンドルに標準入力などを代入する場合、my $fh = 'STDOUT'; ではダメで、my $fh ...
