Changeset 27442

Show
Ignore:
Timestamp:
12/26/08 15:30:16 (4 years ago)
Author:
otsune
Message:

update RSS feed

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • websites/perl-users.jp/html/articles/advent-calendar/adventcal.rss

    r27285 r27442  
    55    <link>http://perl-users.jp/articles/advent-calendar/2008/index.html</link> 
    66    <title>JPerl Advent Calendar 2008</title> 
    7     <pubDate>Tue, 23 Dec 2008 15:48:14 +0900</pubDate> 
     7    <pubDate>Fri, 26 Dec 2008 15:13:04 +0900</pubDate> 
     8    <item> 
     9      <author>nobody@example.com</author> 
     10      <dc:creator>nobody@example.com</dc:creator> 
     11      <link>http://perl-users.jp/articles/advent-calendar/2008/25.html</link> 
     12      <description>バイナリファイルを解析するPerlといえばテキスト処理や正規表現が得意で、バイナリを扱うような話についてはあまり聞かない印象があります。Perlが持つ関数pack/unpack等でもバイナリ処理は可能ですが、今回はData::ParseBinaryを使ってバイナリファイルを気軽に解析してみましょう。基本ファイルからストリームを作る解析したいファイルをData::ParseBinaryで扱えるストリームに変換します。use Data::ParseBinary; 
     13my $stream = CreateStreamReader(File =&gt; $file_handle); 
     14解析したい構造を定義するStruct関数で解析したい構造を定義します。Struct以下には基本データ型やコンテナ型、ビット/バイトパディング型、制御構文型等を使用できます。各型に指定したラベルが解析結果として得られるハッシュのキーとなります。my $your_data_structure = Struct('YOUR_DATA_STRUCTURE', 
     15    UBInt8('length'), 
     16    Array(sub { $_-&gt;ctx-&gt;{length}}, UBInt8('data')), 
     17); 
     18定義した構造を元にストリームを解析する解析したい構造に対してストリームを渡して解析を開始します。解析結果はハッシュとして返されます。my $data = $your_data_structure-&gt;parse($stream); 
     19#  結果例 
     20#  $data = { 
     21#      'YOUT_DATA_STRUCTURE' =&gt; { 
     22#          'length' =&gt; 10, 
     23#          'data' =&gt; [ 
     24#                     1, 
     25#                     2, 
     26#                     ..., 
     27#                    ], 
     28#          }, 
     29#  } 
     30例:FLVファイルを解析する例として、Flashで扱う映像ファイルフォーマットであるFLVファイルを途中まで解析してみます。こちらの仕様書(PDF)を見ながらStruct中を眺めるとやってることがわかると思います。長くなりそうなので途中から詳細はn byteデータチャンクとして扱い、その先を具体的に解析しないようにしています。興味を持たれたらコメントアウト部分を修正して続きを解析してみてください。#!/usr/bin/env perl 
     31use strict; 
     32use warnings; 
     33 
     34package FLV::Parser; 
     35use Data::ParseBinary; 
     36 
     37sub parse { 
     38    my($self, $file) = @_; 
     39 
     40    my $s = 
     41    Struct('FLV', 
     42        header(), 
     43        body(), 
     44    ); 
     45    open my $fh, '&lt;', $file; 
     46    binmode $fh; 
     47    my $stream = CreateStreamReader(File =&gt; $fh); 
     48    my $data = $s-&gt;parse($stream); 
     49    close $fh; 
     50    $data; 
     51} 
     52 
     53sub UBInt24 { 
     54    my($name) = @_; 
     55    Struct($name, 
     56        UBInt8('_b1'), 
     57        UBInt8('_b2'), 
     58        UBInt8('_b3'), 
     59        Value('value', sub { $_-&gt;ctx-&gt;{_b1} &lt;&lt; 16 | $_-&gt;ctx-&gt;{_b2} &lt;&lt; 8 | $_-&gt;ctx-&gt;{_b3} }), 
     60    ); 
     61} 
     62 
     63sub header { 
     64    # 9 byte 
     65    Struct('Header', 
     66        Const(String('Signature', 3), 'FLV'), 
     67        UBInt8('Version'), 
     68        BitStruct('TypeFlags', 
     69            Padding(5), 
     70            Flag('Audio'), 
     71            Padding(1), 
     72            Flag('Video'), 
     73        ), 
     74        UBInt32('DataOffset') 
     75    ); 
     76} 
     77 
     78sub body { 
     79    Struct('Body', 
     80        UBInt32('PreviousTagSize0'), 
     81        GreedyRange(Struct('tags', 
     82            flvtag(), 
     83            UBInt32('PreviousTagSizeN'), 
     84        )), 
     85    ); 
     86} 
     87 
     88sub flvtag { 
     89    Struct('FLVTAG', 
     90        UBInt8('TagType'), 
     91        UBInt24('DataSize'), 
     92        UBInt24('Timestamp'), 
     93        UBInt8('TimestampExtended'), 
     94        UBInt24('StreamID'), 
     95        Switch("Data", sub {$_-&gt;ctx-&gt;{TagType}}, { 
     96            8 =&gt; Struct('AUDIODATA', 
     97                BitStruct('info', 
     98                    BitField('SoundFormat', 4), 
     99                    BitField('SoundRate', 2), 
     100                    BitField('SoundSize', 1), 
     101                    BitField('SoundType', 1), 
     102                ), 
     103                Array(sub{$_-&gt;ctx(1)-&gt;{DataSize}-&gt;{value} - 1}, UBInt8('SoundData')), 
     104            ), 
     105            9 =&gt; Struct('VIDEODATA', 
     106                BitStruct('info', 
     107                    BitField('FrameType', 4), 
     108                    BitField('CodecID', 4), 
     109                ), 
     110                Array(sub{$_-&gt;ctx(1)-&gt;{DataSize}-&gt;{value} - 1}, UBInt8('VideoData')) 
     111            ), 
     112 
     113#            8 =&gt; audiodata(), 
     114#            9 =&gt; videodata(), 
     115#            10 =&gt; scriptdataobject(), 
     116        }, 
     117        default =&gt; Array(sub{$_-&gt;ctx(0)-&gt;{DataSize}-&gt;{value}}, UBInt8('VideoData')) 
     118        ) 
     119    ); 
     120} 
     121 
     122 
     123=head2 commentout 
     124 
     125sub audiodata { 
     126    Struct('AUDIODATA', 
     127        BitStruct('info', 
     128            BitField('SoundFormat', 4), 
     129            BitField('SoundRate', 2), 
     130            BitField('SoundSize', 1), 
     131            BitField('SoundType', 1), 
     132        ), 
     133        Switch('SoundData', sub {$_-&gt;ctx-&gt;{info}-&gt;{SoundFormat}}, { 
     134            10 =&gt; aacaudiodata(), 
     135        }) 
     136    ); 
     137} 
     138sub aacaudiodata { 
     139    Struct( 
     140        UBInt8('AACPacketType'), 
     141        UBInt8('Data', n) 
     142    ); 
     143} 
     144sub videodata { 
     145    Struct('VIDEODATA', 
     146    ); 
     147} 
     148sub scriptdataobject { 
     149    Struct('SCRIPTDATAOBJECT', 
     150    ); 
     151} 
     152 
     153=cut 
     154 
     155package main; 
     156use Data::Dumper; 
     157 
     158my $data = FLV::Parser-&gt;parse('foo.flv'); 
     159print Dumper $data; 
     160C言語でバイナリ解析する場合に比べると、細かい構造体単位でstruct定義を分ける必要がなく、複雑な構造であっても見た目に理解しやすいのがいいところです。制御構文のように使える関数もあるので、「bit 31から28の値が0001なら構造A、0010なら構造Bとして次のN Byteを解析する」というような処理も書きやすいです。処理速度は速くないのでリアルタイムで処理するような用途には向きませんが、バイナリエディタで入れ子になったデータ構造のオフセットを確認しながら手動で値を確認するよりわかりやすいでしょう。また仕様書から複雑なデータフォーマットを学ぶ時にも理解の助けとなると思います。Back 
     161</description> 
     162      <dc:date>2008-12-24T18:14:47Z</dc:date> 
     163      <title>バイナリファイルを解析する</title> 
     164      <pubDate>Wed, 24 Dec 2008 18:14:47 -0000</pubDate> 
     165      <content:encoded>&lt;body&gt;&lt;h1&gt;バイナリファイルを解析する&lt;/h1&gt;&lt;p&gt;Perlといえばテキスト処理や正規表現が得意で、バイナリを扱うような話についてはあまり聞かない印象があります。Perlが持つ関数&lt;code&gt;pack&lt;/code&gt;/&lt;code&gt;unpack&lt;/code&gt;等でもバイナリ処理は可能ですが、今回は&lt;a href="http://search.cpan.org/dist/Data-ParseBinary/"&gt;Data::ParseBinary&lt;/a&gt;を使ってバイナリファイルを気軽に解析してみましょう。&lt;/p&gt;&lt;h2&gt;基本&lt;/h2&gt;&lt;h3&gt;ファイルからストリームを作る&lt;/h3&gt;&lt;p&gt;解析したいファイルをData::ParseBinaryで扱えるストリームに変換します。&lt;/p&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;use Data::ParseBinary; 
     166my $stream = CreateStreamReader(File =&amp;gt; $file_handle); 
     167&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;解析したい構造を定義する&lt;/h3&gt;&lt;p&gt;Struct関数で解析したい構造を定義します。Struct以下には基本データ型やコンテナ型、ビット/バイトパディング型、制御構文型等を使用できます。各型に指定したラベルが解析結果として得られるハッシュのキーとなります。&lt;/p&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;my $your_data_structure = Struct(&amp;apos;YOUR_DATA_STRUCTURE&amp;apos;, 
     168    UBInt8(&amp;apos;length&amp;apos;), 
     169    Array(sub { $_-&amp;gt;ctx-&amp;gt;{length}}, UBInt8(&amp;apos;data&amp;apos;)), 
     170); 
     171&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;定義した構造を元にストリームを解析する&lt;/h3&gt;&lt;p&gt;解析したい構造に対してストリームを渡して解析を開始します。解析結果はハッシュとして返されます。&lt;/p&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;my $data = $your_data_structure-&amp;gt;parse($stream); 
     172#  結果例 
     173#  $data = { 
     174#      &amp;apos;YOUT_DATA_STRUCTURE&amp;apos; =&amp;gt; { 
     175#          &amp;apos;length&amp;apos; =&amp;gt; 10, 
     176#          &amp;apos;data&amp;apos; =&amp;gt; [ 
     177#                     1, 
     178#                     2, 
     179#                     ..., 
     180#                    ], 
     181#          }, 
     182#  } 
     183&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;例:FLVファイルを解析する&lt;/h2&gt;&lt;p&gt;例として、Flashで扱う映像ファイルフォーマットであるFLVファイルを途中まで解析してみます。&lt;a href="http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v9.pdf"&gt;こちらの仕様書(PDF)&lt;/a&gt;を見ながらStruct中を眺めるとやってることがわかると思います。&lt;/p&gt;&lt;p&gt;長くなりそうなので途中から詳細はn byteデータチャンクとして扱い、その先を具体的に解析しないようにしています。興味を持たれたらコメントアウト部分を修正して続きを解析してみてください。&lt;/p&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;#!/usr/bin/env perl 
     184use strict; 
     185use warnings; 
     186 
     187package FLV::Parser; 
     188use Data::ParseBinary; 
     189 
     190sub parse { 
     191    my($self, $file) = @_; 
     192 
     193    my $s = 
     194    Struct(&amp;apos;FLV&amp;apos;, 
     195        header(), 
     196        body(), 
     197    ); 
     198    open my $fh, &amp;apos;&amp;lt;&amp;apos;, $file; 
     199    binmode $fh; 
     200    my $stream = CreateStreamReader(File =&amp;gt; $fh); 
     201    my $data = $s-&amp;gt;parse($stream); 
     202    close $fh; 
     203    $data; 
     204} 
     205 
     206sub UBInt24 { 
     207    my($name) = @_; 
     208    Struct($name, 
     209        UBInt8(&amp;apos;_b1&amp;apos;), 
     210        UBInt8(&amp;apos;_b2&amp;apos;), 
     211        UBInt8(&amp;apos;_b3&amp;apos;), 
     212        Value(&amp;apos;value&amp;apos;, sub { $_-&amp;gt;ctx-&amp;gt;{_b1} &amp;lt;&amp;lt; 16 | $_-&amp;gt;ctx-&amp;gt;{_b2} &amp;lt;&amp;lt; 8 | $_-&amp;gt;ctx-&amp;gt;{_b3} }), 
     213    ); 
     214} 
     215 
     216sub header { 
     217    # 9 byte 
     218    Struct(&amp;apos;Header&amp;apos;, 
     219        Const(String(&amp;apos;Signature&amp;apos;, 3), &amp;apos;FLV&amp;apos;), 
     220        UBInt8(&amp;apos;Version&amp;apos;), 
     221        BitStruct(&amp;apos;TypeFlags&amp;apos;, 
     222            Padding(5), 
     223            Flag(&amp;apos;Audio&amp;apos;), 
     224            Padding(1), 
     225            Flag(&amp;apos;Video&amp;apos;), 
     226        ), 
     227        UBInt32(&amp;apos;DataOffset&amp;apos;) 
     228    ); 
     229} 
     230 
     231sub body { 
     232    Struct(&amp;apos;Body&amp;apos;, 
     233        UBInt32(&amp;apos;PreviousTagSize0&amp;apos;), 
     234        GreedyRange(Struct(&amp;apos;tags&amp;apos;, 
     235            flvtag(), 
     236            UBInt32(&amp;apos;PreviousTagSizeN&amp;apos;), 
     237        )), 
     238    ); 
     239} 
     240 
     241sub flvtag { 
     242    Struct(&amp;apos;FLVTAG&amp;apos;, 
     243        UBInt8(&amp;apos;TagType&amp;apos;), 
     244        UBInt24(&amp;apos;DataSize&amp;apos;), 
     245        UBInt24(&amp;apos;Timestamp&amp;apos;), 
     246        UBInt8(&amp;apos;TimestampExtended&amp;apos;), 
     247        UBInt24(&amp;apos;StreamID&amp;apos;), 
     248        Switch(&amp;quot;Data&amp;quot;, sub {$_-&amp;gt;ctx-&amp;gt;{TagType}}, { 
     249            8 =&amp;gt; Struct(&amp;apos;AUDIODATA&amp;apos;, 
     250                BitStruct(&amp;apos;info&amp;apos;, 
     251                    BitField(&amp;apos;SoundFormat&amp;apos;, 4), 
     252                    BitField(&amp;apos;SoundRate&amp;apos;, 2), 
     253                    BitField(&amp;apos;SoundSize&amp;apos;, 1), 
     254                    BitField(&amp;apos;SoundType&amp;apos;, 1), 
     255                ), 
     256                Array(sub{$_-&amp;gt;ctx(1)-&amp;gt;{DataSize}-&amp;gt;{value} - 1}, UBInt8(&amp;apos;SoundData&amp;apos;)), 
     257            ), 
     258            9 =&amp;gt; Struct(&amp;apos;VIDEODATA&amp;apos;, 
     259                BitStruct(&amp;apos;info&amp;apos;, 
     260                    BitField(&amp;apos;FrameType&amp;apos;, 4), 
     261                    BitField(&amp;apos;CodecID&amp;apos;, 4), 
     262                ), 
     263                Array(sub{$_-&amp;gt;ctx(1)-&amp;gt;{DataSize}-&amp;gt;{value} - 1}, UBInt8(&amp;apos;VideoData&amp;apos;)) 
     264            ), 
     265 
     266#            8 =&amp;gt; audiodata(), 
     267#            9 =&amp;gt; videodata(), 
     268#            10 =&amp;gt; scriptdataobject(), 
     269        }, 
     270        default =&amp;gt; Array(sub{$_-&amp;gt;ctx(0)-&amp;gt;{DataSize}-&amp;gt;{value}}, UBInt8(&amp;apos;VideoData&amp;apos;)) 
     271        ) 
     272    ); 
     273} 
     274 
     275 
     276=head2 commentout 
     277 
     278sub audiodata { 
     279    Struct(&amp;apos;AUDIODATA&amp;apos;, 
     280        BitStruct(&amp;apos;info&amp;apos;, 
     281            BitField(&amp;apos;SoundFormat&amp;apos;, 4), 
     282            BitField(&amp;apos;SoundRate&amp;apos;, 2), 
     283            BitField(&amp;apos;SoundSize&amp;apos;, 1), 
     284            BitField(&amp;apos;SoundType&amp;apos;, 1), 
     285        ), 
     286        Switch(&amp;apos;SoundData&amp;apos;, sub {$_-&amp;gt;ctx-&amp;gt;{info}-&amp;gt;{SoundFormat}}, { 
     287            10 =&amp;gt; aacaudiodata(), 
     288        }) 
     289    ); 
     290} 
     291sub aacaudiodata { 
     292    Struct( 
     293        UBInt8(&amp;apos;AACPacketType&amp;apos;), 
     294        UBInt8(&amp;apos;Data&amp;apos;, n) 
     295    ); 
     296} 
     297sub videodata { 
     298    Struct(&amp;apos;VIDEODATA&amp;apos;, 
     299    ); 
     300} 
     301sub scriptdataobject { 
     302    Struct(&amp;apos;SCRIPTDATAOBJECT&amp;apos;, 
     303    ); 
     304} 
     305 
     306=cut 
     307 
     308package main; 
     309use Data::Dumper; 
     310 
     311my $data = FLV::Parser-&amp;gt;parse(&amp;apos;foo.flv&amp;apos;); 
     312print Dumper $data; 
     313&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;C言語でバイナリ解析する場合に比べると、細かい構造体単位でstruct定義を分ける必要がなく、複雑な構造であっても見た目に理解しやすいのがいいところです。制御構文のように使える関数もあるので、「bit 31から28の値が0001なら構造A、0010なら構造Bとして次のN Byteを解析する」というような処理も書きやすいです。&lt;/p&gt;&lt;p&gt;処理速度は速くないのでリアルタイムで処理するような用途には向きませんが、バイナリエディタで入れ子になったデータ構造のオフセットを確認しながら手動で値を確認するよりわかりやすいでしょう。また仕様書から複雑なデータフォーマットを学ぶ時にも理解の助けとなると思います。&lt;/p&gt;&lt;p&gt;&lt;a href="http://perl-users.jp/articles/advent-calendar/2008/"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/body&gt; 
     314</content:encoded> 
     315      <dcterms:modified>2008-12-24T18:14:47Z</dcterms:modified> 
     316      <guid isPermaLink="false">tag:perl-users.jp,2006:http://perl-users.jp/articles/advent-calendar/2008/25.html</guid> 
     317    </item> 
     318    <item> 
     319      <author>nobody@example.com</author> 
     320      <dc:creator>nobody@example.com</dc:creator> 
     321      <link>http://perl-users.jp/articles/advent-calendar/2008/24.html</link> 
     322      <description>関数をラップするウェブサービス等のAPI とやり取りするモジュールを使って開発している際、デバッグのためAPI からのレスポンスをのぞき見たいときがあると思います(自分はさっきありました)。そんなとき、関数をラップすると便利です。型グロブmy $orig_request = LWP::UserAgent-&gt;can('request'); 
     323*LWP::UserAgent::request = sub { 
     324    use Data::Dumper; 
     325    my $response = $orig_request-&gt;(@_); 
     326    print Dumper($response); 
     327    return $response; 
     328}; 
     329Hook::LexWrapuse Hook::LexWrap; 
     330wrap 'LWP::UserAgent::request', 
     331    post =&gt; sub { 
     332        use Data::Dumper; 
     333        my $response = $_[-1]; 
     334        print Dumper($response); 
     335}; 
     336各ラッパー関数にはラップ元の関数と同じ引数リストが渡されます。加えて$_[-1]に関数の戻り値が設定されます。$_[-1]を変更することで関数の最終的な戻り値を変更できます。つぎはkoyachiさんお願いします。Back 
     337</description> 
     338      <dc:date>2008-12-24T04:12:13Z</dc:date> 
     339      <title>関数をラップする</title> 
     340      <pubDate>Wed, 24 Dec 2008 04:12:13 -0000</pubDate> 
     341      <content:encoded>&lt;body&gt;&lt;h1&gt;関数をラップする&lt;/h1&gt;&lt;p&gt;ウェブサービス等のAPI とやり取りするモジュールを使って開発している際、デバッグのためAPI からのレスポンスをのぞき見たいときがあると思います(自分はさっきありました)。&lt;/p&gt;&lt;p&gt;そんなとき、関数をラップすると便利です。&lt;/p&gt;&lt;h2&gt;型グロブ&lt;/h2&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;my $orig_request = LWP::UserAgent-&amp;gt;can(&amp;apos;request&amp;apos;); 
     342*LWP::UserAgent::request = sub { 
     343    use Data::Dumper; 
     344    my $response = $orig_request-&amp;gt;(@_); 
     345    print Dumper($response); 
     346    return $response; 
     347}; 
     348&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;&lt;a href="http://search.cpan.org/perldoc?Hook::LexWrap"&gt;Hook::LexWrap&lt;/a&gt;&lt;/h2&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;use Hook::LexWrap; 
     349wrap &amp;apos;LWP::UserAgent::request&amp;apos;, 
     350    post =&amp;gt; sub { 
     351        use Data::Dumper; 
     352        my $response = $_[-1]; 
     353        print Dumper($response); 
     354}; 
     355&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;各ラッパー関数にはラップ元の関数と同じ引数リストが渡されます。加えて&lt;code&gt;$_[-1]&lt;/code&gt;に関数の戻り値が設定されます。&lt;/p&gt;&lt;p&gt;&lt;code&gt;$_[-1]&lt;/code&gt;を変更することで関数の最終的な戻り値を変更できます。&lt;/p&gt;&lt;p&gt;つぎは&lt;a href="http://tako3.com/http://buffr.org/"&gt;koyachi&lt;/a&gt;さんお願いします。&lt;/p&gt;&lt;p&gt;&lt;a href="http://perl-users.jp/articles/advent-calendar/2008/"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/body&gt; 
     356</content:encoded> 
     357      <dcterms:modified>2008-12-24T04:12:13Z</dcterms:modified> 
     358      <guid isPermaLink="false">tag:perl-users.jp,2006:http://perl-users.jp/articles/advent-calendar/2008/24.html</guid> 
     359    </item> 
    8360    <item> 
    9361      <author>nobody@example.com</author> 
     
    117469}関連してそうなCPANモジュールhttp://search.cpan.org/dist/Memoize/http://search.cpan.org/dist/Method-Cached/http://search.cpan.org/dist/Attribute-Cached/http://search.cpan.org/~dankogai/Attribute-Util-1.03/次はyoupy(ブラクラ注意)さんに回したいと思います。Back 
    118470</description> 
    119       <dc:date>2008-12-23T06:40:32Z</dc:date> 
     471      <dc:date>2008-12-23T16:53:05Z</dc:date> 
    120472      <title>キャッシュしよう</title> 
    121       <pubDate>Tue, 23 Dec 2008 06:40:32 -0000</pubDate> 
     473      <pubDate>Tue, 23 Dec 2008 16:53:05 -0000</pubDate> 
    122474      <content:encoded>&lt;body&gt;&lt;h1&gt;キャッシュしよう&lt;/h1&gt;&lt;p&gt;京都観光で散財しすぎて貯金がないmalaです。こんにちは。キャッシュの話を書きます。&lt;/p&gt;&lt;h2&gt;色んなキャッシュがあります&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;データベースから引く前にmemcachedから取得したり&lt;/li&gt;&lt;li&gt;テンプレートエンジンのレンダリング結果をキャッシュしたり&lt;/li&gt;&lt;li&gt;各種ウェブサービスのリクエスト結果をキャッシュしたり&lt;/li&gt;&lt;li&gt;その他諸々CPUを食ったり時間のかかる処理をキャッシュしたり&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;簡単に思いつくのはこの程度ですが、スケーラブルなウェブサイトを構築するには常識的に考えてそんなのキャッシュしねーだろうというようなものをキャッシュする必要があります。&lt;/p&gt;&lt;h2&gt;DateTimeをキャッシュしよう&lt;/h2&gt;&lt;p&gt;同じ時刻に対するDateTimeオブジェクトをキャッシュします。&lt;/p&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;package MyDateTime; 
    123475use strict; 
     
    146498now         3086/s         --       -95% 
    147499now_cached 66667/s      2060%         -- 
    148 &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;現在時刻を生成しまくるという極端なケースですが、20倍ぐらい高速化することができます。 オリジナルのDateTime-&amp;gt;nowを呼び出すと、DateTimeオブジェクトを一回生成するあたり、0.3msぐらいかかっているということがわかります。 たかが0.3msですが、Feedを解析したりしていると10000件ぐらいのDateTimeオブジェクトを作ったりすることも良くありますから、合計で3秒かかったりして、結構無視できなかったりします。&lt;/p&gt;&lt;p&gt;ちなみにこのコードはtimezone等、他の引数を全く考慮しておらず、かなりいい加減な代物ですから、注意してください。 cloneしているのはDateTimeオブジェクトを破壊的に使う可能性があるからです。&lt;/p&gt;&lt;h2&gt;Method::Cachedを使って手軽に高速化&lt;/h2&gt;&lt;p&gt;こういったコードをいちいち書くのが面倒くさいのでbonnnuさんの&lt;a href="http://coderepos.org/share/browser/lang/perl/Method-Cached/trunk"&gt;Method::Cached&lt;/a&gt;を試してみました。memoizeとかmemoiseとか呼ばれる奴ですね。&lt;/p&gt;&lt;p&gt;attributeを使ってキャッシュの有効期限と、引数のシリアライズルールを記述してやると、そのメソッドの結果がキャッシュされるようになります。&lt;/p&gt;&lt;p&gt;サンプルコード。&lt;/p&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;package MyDateTime2; 
     500&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;現在時刻を生成しまくるという極端なケースですが、20倍ぐらい高速化することができます。 オリジナルの&lt;code&gt;DateTime-&amp;gt;now&lt;/code&gt;を呼び出すと、DateTimeオブジェクトを一回生成するあたり、0.3msぐらいかかっているということがわかります。 たかが0.3msですが、Feedを解析したりしていると10000件ぐらいのDateTimeオブジェクトを作ったりすることも良くありますから、合計で3秒かかったりして、結構無視できなかったりします。&lt;/p&gt;&lt;p&gt;ちなみにこのコードはtimezone等、他の引数を全く考慮しておらず、かなりいい加減な代物ですから、注意してください。 cloneしているのはDateTimeオブジェクトを破壊的に使う可能性があるからです。&lt;/p&gt;&lt;h2&gt;Method::Cachedを使って手軽に高速化&lt;/h2&gt;&lt;p&gt;こういったコードをいちいち書くのが面倒くさいのでbonnnuさんの&lt;a href="http://coderepos.org/share/browser/lang/perl/Method-Cached/trunk"&gt;Method::Cached&lt;/a&gt;を試してみました。memoizeとかmemoiseとか呼ばれる奴ですね。&lt;/p&gt;&lt;p&gt;attributeを使ってキャッシュの有効期限と、引数のシリアライズルールを記述してやると、そのメソッドの結果がキャッシュされるようになります。&lt;/p&gt;&lt;p&gt;サンプルコード。&lt;/p&gt;&lt;pre class="lang-perl"&gt;&lt;code&gt;package MyDateTime2; 
    149501use strict; 
    150502use base qw(DateTime); 
     
    227579}&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;関連してそうなCPANモジュール&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/dist/Memoize/"&gt;http://search.cpan.org/dist/Memoize/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/dist/Method-Cached/"&gt;http://search.cpan.org/dist/Method-Cached/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/dist/Attribute-Cached/"&gt;http://search.cpan.org/dist/Attribute-Cached/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/~dankogai/Attribute-Util-1.03/"&gt;http://search.cpan.org/~dankogai/Attribute-Util-1.03/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;次は&lt;a href="http://d.hatena.ne.jp/youpy/"&gt;youpy&lt;/a&gt;(ブラクラ注意)さんに回したいと思います。&lt;/p&gt;&lt;p&gt;&lt;a href="http://perl-users.jp/articles/advent-calendar/2008/"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/body&gt; 
    228580</content:encoded> 
    229       <dcterms:modified>2008-12-23T06:40:32Z</dcterms:modified> 
     581      <dcterms:modified>2008-12-23T16:53:05Z</dcterms:modified> 
    230582      <guid isPermaLink="false">tag:perl-users.jp,2006:http://perl-users.jp/articles/advent-calendar/2008/23.html</guid> 
    231583    </item> 
     
    284636なんと1/4がワンライナーでした。みなさんも是非。そうそう。次はid:malaにてお願いします。Dan the One-Liner MongerSee Also:perldoc perlrunBack 
    285637</description> 
    286       <dc:date>2008-12-23T06:40:32Z</dc:date> 
     638      <dc:date>2008-12-23T16:53:05Z</dc:date> 
    287639      <title>一行野郎(one-liner)はperlにおまかせ</title> 
    288       <pubDate>Tue, 23 Dec 2008 06:40:32 -0000</pubDate> 
     640      <pubDate>Tue, 23 Dec 2008 16:53:05 -0000</pubDate> 
    289641      <content:encoded>&lt;body&gt;&lt;div class="hentry"&gt;&lt;h1 class="entry-title"&gt;一行野郎(one-liner)はperlにおまかせ&lt;/h1&gt;&lt;div class="entry-content"&gt;&lt;h2&gt;序文&lt;/h2&gt;&lt;ul style="list-style-image:url(http://www.kotono8.com/favicon.ico)"&gt;&lt;li&gt;&lt;a href="http://www.kotono8.com/2008/12/21if-programming-languages-were-religions.html" target="_blank"&gt;もしもプログラミング言語が宗教だったら……(全訳版)[絵文録ことのは]2008/12/21&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;によると、ブードゥー教徒らしい &lt;span class="vcard"&gt; &lt;span class="fn nickname"&gt;dankogai&lt;/span&gt; &lt;/span&gt; です。 ブードゥー教徒らしく、「上司があなたに金曜夜21時に緊急の仕事を命ずるときにしばしば使われる」呪文をここでまとめておくことにします。 &lt;/p&gt;&lt;h2&gt;基本中の基本&lt;/h2&gt;&lt;p&gt;コマンドとしての&lt;code&gt;perl&lt;/code&gt;は、スイッチがない場合、引数はスクリプト名として扱われます。&lt;/p&gt;&lt;pre class="lang-sh"&gt;&lt;code&gt;&lt;span class="nocode"&gt;% &lt;/span&gt;cat hello.pl 
    290642&lt;span class="nocode"&gt;print &amp;quot;Hello, world!\n&amp;quot;; 
     
    337689&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;なんと1/4がワンライナーでした。みなさんも是非。&lt;/p&gt;&lt;p&gt;そうそう。次はid:malaにてお願いします。&lt;/p&gt;&lt;p&gt;Dan the One-Liner Monger&lt;/p&gt;&lt;p&gt;See Also:&lt;/p&gt;&lt;ul style="list-style-image:url(http://search.cpan.org/favicon.ico)"&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/perldoc?perlrun" target="_blank"&gt;perldoc perlrun&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://perl-users.jp/articles/advent-calendar/2008/"&gt;Back&lt;/a&gt;&lt;/p&gt;&lt;/body&gt; 
    338690</content:encoded> 
    339       <dcterms:modified>2008-12-23T06:40:32Z</dcterms:modified> 
     691      <dcterms:modified>2008-12-23T16:53:05Z</dcterms:modified> 
    340692      <guid isPermaLink="false">tag:perl-users.jp,2006:http://perl-users.jp/articles/advent-calendar/2008/22.html</guid> 
    341693    </item>