バッファリング処理を高速化したいです。
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レコード取得は正規表現で探しているのですがこちらはもうすこし調べてからにしようと思います。
No.1ベストアンサー
- 回答日時:
確かに文字列の連結とか切り出しで効率は悪そうですが、ここを変えても、劇的には速くならないような気がします。
試しに、ファイルを読み込むだけの処理を書いてみて下さい。
次に、正規表現でレコード長を得ている処理を飛ばすため、正規表現の変わりに、レコード長を適当な数値に置き換えてみて下さい。
多分、ネックとなっているのは、正規表現の部分か、読み込みのどちらかだと思うので、たいして変わらないと思います。
その場合、正規表現の見直しとなります。
また、両者で速度が、大きく変わるのであれば、使用しているバージョンと、期待されるレコード長の平均サイズと、最大サイズを提示して下さい。
substr()の問題では無いということでいろいろと実験してみた結果、
正規表現やsubstr()よりも複数ファイル読み込んだときにおこなうレコード件数の
集計部分が思った以上に時間かかっているということがわかりました。
集計部分をけずったら処理時間が1/3程度にまで減りました。
(10分強 → 3分強)
連想配列を使用してヘッダ種別ごとの件数をカウントしているので
このあたりを工夫できないか考えてみます。
ちなみに、
perl version は 5.8.8
入力ファイル数 : 7000くらい(合計サイズは440MBくらい)
入力レコード件数: 82万くらい
レコード長の平均は 512 バイトで 範囲は128 ~ 3072でした。
ヘッダの種類は 70種くらいです。
コメントありがとうございました。
No.4
- 回答日時:
媒体やファイルシステムによっても違いますが、7000もファイルがあると、オープンとクローズだけでも、そこそこ時間が掛かるかもしれません。
念のため、確認することをお勧めします。
集計処理を改善しても変わりませんでした。
すみません。実は原因は全く違うところでしたorz
入力ファイルがヘッダ種別から始まるか判断するのに
cat -vt FILE | head -c -n 10 みたいな処理になっていて
判定後もファイルの内容を最後までよむ感じになっていました。
このチェックの方式を変更したところ、最初に相談したときのソースコードから
5-6行修正するだけで処理時間が10分強 → 4分弱まで減りました。
1ファイルにまとめたときは3分程度だったので
あとの1分は集計部分なのかもしれませんが、7000ファイルで1分程度なら
一つ0.5秒程度だしまあいいかと思います。
4分程度なら本物のデータつかっても20分もあれば終わるでしょうから
待てない時間ではないので妥協しようと思います。
ありがとうございました。
No.3
- 回答日時:
なるほど、かなり難しいフォーマットであることがわかりました。
以下のようにすれば、もう少し効率化できるかもしれませんが、試していません。
# ヘッダごとにスキップする長さを書く
my %templates = (
hd1 => 'x7',
hd2 => 'x4',
hd3 => 'x16'
....
);
# ヘッダ名取得
$header = xx;
# レコードの中身をスキップする
$buffer = unpack $templates{$header} . 'a*' , $buffer;
アプリの処理結果を検証するためのツールなので
こんなめんどくさいことになっています;;
1ファイルだけにすると処理時間が圧倒に減ることに着目して
いろいろと削って検証した結果、読み込みやカウントの部分には
あんまり大きな問題はなくて、それ以前にロジックの問題でした。
問題点を修正したところ、4分弱までは短縮できたのでこれでしばらく運用してみようと思います。
ありがとうございました。
No.2
- 回答日時:
どんなフォーマットですか?
フォーマットですが
改行コードなしで複数種類のヘッダがあります。
ヘッダにつづくデータ部分には改行コードが含まれていたりします。
レコード長の情報は別に存在しますが参照できません。
その代わり、ヘッダと同じ文字列はデータ部には現れない前提です。
現れた結果、件数が想定外になってもその部分に関しては問題ないことになってします。
このツールの目的は
ファイル単位ヘッダ種別ごとにレコード件数を出力するのと
最後にヘッダ種別ごとのレコード件数合計を出力することです。
ファイル内の書式例です。
hd1zzzzzzzhd2xxxxhd3gggggggggggggggghd1zzzzzzz
hd? の部分がヘッダになります。
ヘッダは全部で70種類くらいありますがすべてのヘッダがファイル内に含まれているとは限りません。
ファイル数は7000ファイルくらいが上限ですが、ファイルサイズの合計は4GB程度になります。
別の回答に記述しましたが、性能が出ない原因はレコード件数の集計処理にあるようでした。
同じデータ量でも1ファイルだけにすると処理時間が1/3程度になることから
レコード件数の合計を管理している連想配列とファイル単位のレコード件数を管理している連想配列の加算処理に問題があるのかもしれません。
substr()を使わなくてもよいように読み込んだバッファを正規表現 1回で レコード単位の配列に入力する処理へ変更してみましたがかえって遅くなってしまいました。
# shiftとかpopしているせいかもしれませんけど。。。
substr()を使って地道に処理する方が早いようです。
#ん~substr()って優秀なんですね。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP クエリObjectをforeachで回す時に、次のレコードへ移動せずに次のレコードを取得したい 2 2022/07/28 15:29
- Visual Basic(VBA) Excel VBA 複数ブックシートごとにデータを統合する方法について 4 2022/05/20 14:23
- Visual Basic(VBA) 複数ブックの統合について Excel VBA 1 2022/05/13 09:48
- その他(データベース) Accessフォームからパラメーターで表示したレコードを指定のExcelのセルへ転送する方法について 2 2022/08/22 18:04
- Excel(エクセル) 非表示にしたい行をグループ化して折り畳み 4 2022/09/17 20:17
- PHP if(preg_match("/[^0-9]/",$gu_d)){意味を教えてください。 1 2022/05/06 05:37
- ドメイン・サーバー・クラウドサービス 独自ドメインでのNSレコード設定 1 2023/07/12 18:36
- Visual Basic(VBA) ExcelからAccessのテーブルに書き込む時に時間がかかる 1 2022/10/14 20:38
- スピーカー・コンポ・ステレオ ハイレゾとレコードの音質差について 宜しくお願いします。 レコードにはCDでは録音できない倍音成分が 21 2022/06/28 10:04
- Visual Basic(VBA) 複数csvを横に追加していくマクロについて 2 2023/04/25 09:19
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VB6で、長い時間かかる処理...
-
実行中の変数の中身をイミディ...
-
Application.ScreenUpdating = ...
-
どちのほうがすきですか?
-
JSONで文字列が長い時
-
16進の10進変換について
-
セレクトボックスの中を一部隠...
-
メモリをアドレスを直接指定し...
-
<SELECT>タグの折り返し
-
formで特定のinputを送信しない...
-
Python - Excel で Webからデー...
-
フォームの日本語が文字化け
-
UWSC:ポップアップウインドウ...
-
int(input("○○"))の使い方
-
文字の横にプルダウンを表示さ...
-
ACCESS テキストボックスを隙...
-
複数列を持ったリストボックス...
-
パイソンのクラスについて
-
パイソンのクラスのブログラム
-
数値かどうかの判定方法
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
初回起動のみ判別したい
-
VB6で、長い時間かかる処理...
-
実行中の変数の中身をイミディ...
-
処理終了後、他のページへジャ...
-
UWSC SLCTBOXもしくはSELECTに...
-
C言語のflagの使い方が分かりま...
-
SetDlgItemInt( ) c++
-
perl:ループのカウンタ変数の値...
-
arduino の割り込み処理について
-
夕方くらいから急にGoogle検索...
-
フォームデータ内の特定文字列...
-
正規表現。文の表示の際、マッ...
-
VBAのCallステートメントについて
-
処理をした後にとばしたい場所...
-
Perlでプロンプトを作成する方...
-
問題作成のWebアプリの作り方を...
-
10000通りのシリアル番号を生成...
-
数値計算の際、1000以下は端数...
-
C言語のプログラミング
-
自動的にエスケープを付けて別...
おすすめ情報