プロが教えるわが家の防犯対策術!

バッファリング処理を高速化したいです。

perlのプログラムで性能がでなくて困っています。

ファイルの中身からレコードヘッダを検索しつつ可変長なレコードの件数をカウントするツールで
バッファリングというかストリーミングっぽい処理をしているのですが
思いの外、性能が出ずこまっています。
(600MBのテキストで10分弱くらい、予定では1分程度で終わる見込みでした)

とりあえず、非効率そうなのは、1レコード取得する部分と下記のようなバッファシフトの部分くらいなのですが
バッファシフトについて何かもっとよい書き方はありますでしょうか?

処理的なイメージはこんな感じになっています。
LOOP_A:
read(IN, $readbuf, 10240);
$buf .= $readbuf;
LOOP_B:
... レコード長の計算
... バッファ内にレコード長以上なければ、LOOP_Aへ
$buf = substr($buf,$reclen); # 処理済みレコードの削除
LOOP_B へ

substr()の部分を
C的にいうと先頭アドレスだけ移動するような書き方ができれば一番なのですが~

1レコード取得は正規表現で探しているのですがこちらはもうすこし調べてからにしようと思います。

A 回答 (4件)

確かに文字列の連結とか切り出しで効率は悪そうですが、ここを変えても、劇的には速くならないような気がします。


試しに、ファイルを読み込むだけの処理を書いてみて下さい。
次に、正規表現でレコード長を得ている処理を飛ばすため、正規表現の変わりに、レコード長を適当な数値に置き換えてみて下さい。
多分、ネックとなっているのは、正規表現の部分か、読み込みのどちらかだと思うので、たいして変わらないと思います。
その場合、正規表現の見直しとなります。
また、両者で速度が、大きく変わるのであれば、使用しているバージョンと、期待されるレコード長の平均サイズと、最大サイズを提示して下さい。
    • good
    • 0
この回答へのお礼

substr()の問題では無いということでいろいろと実験してみた結果、
正規表現やsubstr()よりも複数ファイル読み込んだときにおこなうレコード件数の
集計部分が思った以上に時間かかっているということがわかりました。
集計部分をけずったら処理時間が1/3程度にまで減りました。
(10分強 → 3分強)

連想配列を使用してヘッダ種別ごとの件数をカウントしているので
このあたりを工夫できないか考えてみます。

ちなみに、
perl version は 5.8.8
入力ファイル数 : 7000くらい(合計サイズは440MBくらい)
入力レコード件数: 82万くらい
レコード長の平均は 512 バイトで 範囲は128 ~ 3072でした。
ヘッダの種類は 70種くらいです。

コメントありがとうございました。

お礼日時:2010/06/03 20:45

媒体やファイルシステムによっても違いますが、7000もファイルがあると、オープンとクローズだけでも、そこそこ時間が掛かるかもしれません。


念のため、確認することをお勧めします。
    • good
    • 0
この回答へのお礼

集計処理を改善しても変わりませんでした。
すみません。実は原因は全く違うところでしたorz

入力ファイルがヘッダ種別から始まるか判断するのに
cat -vt FILE | head -c -n 10 みたいな処理になっていて
判定後もファイルの内容を最後までよむ感じになっていました。

このチェックの方式を変更したところ、最初に相談したときのソースコードから
5-6行修正するだけで処理時間が10分強 → 4分弱まで減りました。

1ファイルにまとめたときは3分程度だったので
あとの1分は集計部分なのかもしれませんが、7000ファイルで1分程度なら
一つ0.5秒程度だしまあいいかと思います。

4分程度なら本物のデータつかっても20分もあれば終わるでしょうから
待てない時間ではないので妥協しようと思います。
ありがとうございました。

お礼日時:2010/06/05 01:21

なるほど、かなり難しいフォーマットであることがわかりました。


以下のようにすれば、もう少し効率化できるかもしれませんが、試していません。

# ヘッダごとにスキップする長さを書く
my %templates = (
hd1 => 'x7',
hd2 => 'x4',
hd3 => 'x16'
....
);

# ヘッダ名取得
$header = xx;

# レコードの中身をスキップする
$buffer = unpack $templates{$header} . 'a*' , $buffer;
    • good
    • 0
この回答へのお礼

アプリの処理結果を検証するためのツールなので
こんなめんどくさいことになっています;;

1ファイルだけにすると処理時間が圧倒に減ることに着目して
いろいろと削って検証した結果、読み込みやカウントの部分には
あんまり大きな問題はなくて、それ以前にロジックの問題でした。

問題点を修正したところ、4分弱までは短縮できたのでこれでしばらく運用してみようと思います。
ありがとうございました。

お礼日時:2010/06/05 01:27

どんなフォーマットですか?

    • good
    • 0
この回答へのお礼

フォーマットですが
改行コードなしで複数種類のヘッダがあります。
ヘッダにつづくデータ部分には改行コードが含まれていたりします。
レコード長の情報は別に存在しますが参照できません。
その代わり、ヘッダと同じ文字列はデータ部には現れない前提です。
現れた結果、件数が想定外になってもその部分に関しては問題ないことになってします。

このツールの目的は
ファイル単位ヘッダ種別ごとにレコード件数を出力するのと
最後にヘッダ種別ごとのレコード件数合計を出力することです。

ファイル内の書式例です。
hd1zzzzzzzhd2xxxxhd3gggggggggggggggghd1zzzzzzz

hd? の部分がヘッダになります。
ヘッダは全部で70種類くらいありますがすべてのヘッダがファイル内に含まれているとは限りません。

ファイル数は7000ファイルくらいが上限ですが、ファイルサイズの合計は4GB程度になります。

別の回答に記述しましたが、性能が出ない原因はレコード件数の集計処理にあるようでした。
同じデータ量でも1ファイルだけにすると処理時間が1/3程度になることから
レコード件数の合計を管理している連想配列とファイル単位のレコード件数を管理している連想配列の加算処理に問題があるのかもしれません。


substr()を使わなくてもよいように読み込んだバッファを正規表現 1回で レコード単位の配列に入力する処理へ変更してみましたがかえって遅くなってしまいました。
# shiftとかpopしているせいかもしれませんけど。。。

substr()を使って地道に処理する方が早いようです。
#ん~substr()って優秀なんですね。

お礼日時:2010/06/03 21:01

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!