5

ファイルからデータベースにデータをロードする成熟したコード本体があります。いくつかのファイル形式があります。これらはすべて固定幅フィールドです。

コードの一部では、Perlunpack()関数を使用して、フィールドを入力データからパッケージ変数に読み取ります。ビジネスロジックは、これらのフィールドを「人間が読める」方法で参照できます。

ファイル読み取りコードは、ファイルを読み取る前に、フォーマット記述から一度生成されます。

スケッチ形式では、生成されたコードは次のようになります。

while ( <> ) {

    # Start of generated code.

    # Here we unpack 2 fields, real code does around 200.
    ( $FIELDS::transaction_date, $FIELDS::customer_id ) = unpack q{A8 A20};

    # Some fields have leading space removed
    # Generated code has one line like this per affected field.
    $FIELDS::customer_id =~ s/^\s+//;

    # End of generated code.

    # Then we apply business logic to the data ...
    if ( $FIELDS::transaction_date eq $today ) {
        push @fields, q{something or other};
    }

    # Write to standard format for bulk load to the database.
    print $fh join( '|', @fields ) . q{\n} or die;
}

コードをプロファイリングすると、時間の約 35% がアンパックと先頭のスペース ストリップに費やされていることがわかります。残りの時間は、データの検証と変換、および出力ファイルへの書き込みに費やされます。

実行時間の 1 ~ 2% を超えるビジネス ロジックの部分はないようです。

問題は、どうにかしてアンパッキングとスペースストリッピングからもう少し速度を上げることができるかということです。できれば、FIELDS パッケージ変数を参照するすべてのコードをリファクタリングする必要はありません。

編集:

それが違いを生む場合

$ perl -v
This is perl, v5.8.0 built for PA-RISC1.1
4

6 に答える 6

7

私は実際にこの問題に何度も何度も対処してきました。解凍はsubstrよりも優れています

スペースを取り除く限り、あなたはかなり困惑しています。その正規表現ハックは、それを行うための「公式」な方法です。unpackステートメントを改良することである程度の効率を得ることができるかもしれません(4桁より長いデータがないと仮定して、なぜフィールドの12桁全体を解凍するのですか?)、それ以外の場合、解析は単なるピタです

フラットデータで頑張ってください。レガシージャンクをはじく、私がそれをどのように嫌うか。

于 2009-10-19T14:13:29.970 に答える
3

このタスクでプロセッサにバインドされていますか? 計算は単純なので、プロセス全体が I/O バウンドである可能性が高いと推測できます。その場合、解凍を高速化するために最適化しても、それほど時間はかかりません。

実際にプロセッサに縛られている場合、説明されている問題はほとんど並列化できるように見えますが、もちろん、問題はビジネス計算の詳細にあります。

于 2009-10-19T14:22:12.517 に答える
1

はい。を使用して抽出するsubstrのが、おそらく最速の方法です。あれは:

$FIELDS::transaction_date = substr $_, 0, 8;
$FIELDS::customer_id      = substr $_, 8, 20;

より速くなる可能性があります。もし私がこのコードを手書きしていたら諦めませんunpackが、もしあなたがコードを生成しているのなら、試してみて測定することもできます.

Perl の unpack() は substr() よりも高速ですか?への回答も参照してください。

先頭のスペースの削除に関してs/^\s+//は、最速の方法である可能性があります。

更新:ベンチマークを実行できなければ、明確なことを言うのは困難です。ただし、次の場合はどうですか。

my  $x  = substr $_, 0, 8;

トリミングを必要としないフィールドの場合

my ($y) = substr($_, 8, 20) =~ /\A\s+(.+?)\s+\z/;

トリミングが必要ですか?

于 2009-10-19T13:56:58.170 に答える
1

単純に並列にします。それは些細なことであり、遠く離れた最新のマシンでも高速になります。

于 2009-10-20T07:33:13.027 に答える
1

これは XS の場合もあります。つまり、C 関数を使用してデータを変更します。データが実際にコピーされるタイミングを手動で制御できるため、これは他の何よりもはるかに高速であると想像できます。
C コンパイラに依存しているため、ビルド プロセスはより難しくなり、追加の統合手順が必要になります。

于 2009-10-19T16:20:05.307 に答える
0

私たちのコードの substr ベースのバージョンのベンチマークは、既存のアンパックよりも約 50% 高速である可能性があることを示唆しています。実際のアプリケーションに配置されたコードを比較すると、substr バージョンでは実行時間が 16% 短縮されました。これは、質問で言及されているベンチマークとプロファイリングに基づいて、私たちが望んでいたものに近いものです。

この最適化は私たちにとって役立つかもしれません。ただし、新しい OS への移行が間近に迫っているため、先に進む前にそこでコードがどのように機能するかを確認します。比較ベンチマークを監視するためのテストを追加しました。

現在のイディオムは次のとおりです。

$FIELDS::transaction_date = substr( $_, 0, 8 ) || '';
$FIELDS::transaction_date =~ s/\s+\z//;
$FIELDS::customer_id = substr( $_, 8, 20 ) || '';
$FIELDS::customer_id =~ s/\s+\z//;

以前と同様に、先頭のスペースを選択的に削除します。

これまでのすべての回答に感謝します。「まったく間違っている」ように見えますが、私たちにとってはうまくいったので、私はシナンのものを受け入れます.

于 2009-10-20T14:39:44.533 に答える