4

固定長レコードのファイルを解析する Perl で書かれたパーサーがあります。レコードの一部は、数字のみで構成された複数の文字列 (これも固定長) で構成されています。文字列内の各文字は、ASCII char ではなく数値としてエンコードされます。つまり、文字列 12345 がある場合、それは (31 32 33 34 35 ではなく) 01 02 03 04 05 としてエンコードされます。

unpack でレコードを解析すると、この特定の部分が として展開され@array = unpack "C44", $sます。次に、 のような単純な結合で必要な文字列を復元します$m = join("", @array)

それが最適なデコード方法かどうか疑問に思っていました。ファイルは非常に大きく、何百万ものレコードがあり、明らかに最適化が可能かどうかを調べようとしました。Profiler は、ほとんどの時間がレコードの解析に費やされていることを示しています (つまり、読み取り、書き込み、およびその他のものは問題ではありません)。解析では、ほとんどの時間がこれらの結合に費やされています。join は非常に効率的な操作であることを他の情報源から覚えています。コードをさらに高速化することが可能か、それともすでに最適化されているかについてのアイデアはありますか? おそらく、代わりにパック/アンパックの組み合わせを使用するなど、何らかの巧妙な方法でこの中間配列を回避することは可能でしょうか?

編集:コード例

最適化しようとするコードは次のようになります。

    while (read(READ, $buf, $rec_l) == $rec_l) {
        my @s = unpack "A24 C44 H8", $buf;
        my $msisdn = substr $s[0], 0, 11;
        my $address = join("", @s[4..14]);
        my $imsi = join("", @s[25..39]);
        my $ts = localtime(hex($s[45]));
    }
4

3 に答える 3

6

テストされていません(忙しくないときに戻って編集します)が、すべての計算を正しく行っていれば、これは機能し、高速になります。

my ($msisdn, $address, $imsi, $ts) = 
    unpack "A11 x13 x3 a10 x10 a15 x5 N", $buf;
$address |= "0" x 10;
$imsi |= "0" x 15
$ts = localtime($ts);
于 2012-05-03T14:16:59.390 に答える
0

私はパック/アンパック初心者ですが、サンプルコードを次のように変更して結合をスキップするのはどうですか:

my $m = unpack "H*", $s ;

クイックテスト:

#!/usr/bin/perl

use strict ;
use Test::More tests => 1 ;

is( unpack("H*", "\x12\x34\x56"),"123456");
于 2012-05-03T11:48:17.037 に答える
0

Perl ではいつものように、速いほど読みにくくなります :-)

join("", unpack("C44", $s))

この変更によってコードが高速化されるとは思えません。すべては、結合関数を呼び出して 1 つのファイル全体を読み取る頻度に依存します。チャンクで作業している場合は、それらのサイズを大きくしてみてください。アンパックとこの配列への結合の間に何らかの操作を行っている場合は、それらをマップ操作で整列させてみてください。ソースコードを投稿すると、ボトルネックを特定しやすくなります。

于 2012-05-03T11:36:46.943 に答える