0

日付ごとに情報を表示するために使用されるperlスクリプトがあります。日付に従ってデータを取得し、フィールド区切り文字「AaBbCc」を持つフラット ファイルとして保持します。

ファイル名は

18-01-13_REPORT
17-01-13_REPORT

レコードは

111 AaBbCc 2222 AaBbCc 3333 AaBbCc etc(each two lines forms a single record)

各ファイルには 5000 を超えるレコードがあります。私のコードを使用すると、レコードを正常に印刷できます。ただし、すべてのレコードを印刷するには 15 分かかります。ここで、コードを最適化して、これらのレコードをより短い時間で印刷したいと考えています。

私のコードを見つけてください

open (FILE,"$filename/$val_REPORT_DATE") 
    or die "Could not read from $filename, program halting.";
local $/ = undef; #get the whole file in to picture
while(<FILE>) {
    chomp $_;
    @fields = split('AaBbCc', $_);
    for ( $i=0 ; $i<$count ; ) {
        print "<tr><td>" . $fields[$i+0] .
              "</td><td>". $fields[$i+1] .
              "</td><td>". $fields[$i+2] .
              "</td><td>". $fields[$i+3] .
              "</td><td>". $fields[$i+4] .
              "</td><td>". $fields[$i+5] .
              "</td><td>". $fields[$i+6] .
                           $fields[$i+7] ."</td></tr>";
        $i = $i + 8;
    }
}

パフォーマンスを向上させるために、すべてのレコードを短時間で印刷するのを手伝ってください

前もって感謝します !!!ビジェイ

4

1 に答える 1

2

コードが遅い理由はいくつかあります。

  1. 使用されているファイル形式は頭がおかしいです。
  2. で検索するすべての要素@fieldsに対して、加算を実行します。これは低レベル言語ではそれほどコストがかかりませんが、Perls スカラーは非常に高価です。

    これは、配列要素の検索を行うオペコード ツリーの多くの部分の 1 つです。

    35               <2> aelem sK/2 ->36
    31                  <1> rv2av sKR/1 ->32        # get actual array
    30                      <#> gv[*fields] s ->31  # get global typeglob
    34                  <2> add[t63] sK/2 ->35      # create new scalar here
    -                       <1> ex-rv2sv sK/1 ->33  # get actual scalar
    32                         <#> gvsv[*i] s ->33  # get global typeglob
    33                      <$> const[IV 7] s ->34
    

    これを、レキシカル変数を使用し、追加を行わない要素ルックアップと比較します。

    c        <2> aelem sK/2 ->d
    a           <0> padav[@fields:47,49] sR ->b     # beautiful
    b           <0> padsv[$i:48,49] s ->c           # beautiful
    
  3. コードのパフォーマンスを向上させるためのベスト プラクティスがいくつかあります。たとえば、my. グローバル変数は別の方法で検索され、はるかに遅くなります (上記を参照)。また、一度にファイル全体を丸呑みする必要はありません。一定のスペースで実行できるのに、なぜそんなに多くのメモリを使用するのでしょうか?

.

#!/usr/bin/perl
use strict; use warnings; # every good script starts with these
use 5.010;

open my $file, "<", $filename or die qq(Couldn't open "$filename": $!):
until (eof $file) {
  # read two lines at a time
  my $line1 = <$file>;
  my $line2 = <$file> // die qq(uneven number of lines in "$filename");
  ...
}

これで、2 つの可能な解決策を入力できます。以下は、データフロー プログラミングを強調するものです (下から上に読んでください)。

print
    "<tr>" . (
       join "" =>
       map  "<td>$_</td>",
       map  {chomp; split /AaBbCc/}
            ($line1, $line2)
    ) . "</tr>\n"
    ;

同じアルゴリズムを次のようにエンコードできます。

chomp($line1, $line2);
my $string = "";
$string .= "<td>$_</td>" for split(/AaBbCc/, $line1), split(/AaBbCc/, $line2);
print "<tr>$string</tr>\n";

特殊変数を悪用することもできます:

chomp($line1, $line2);
my @fields = split(/AaBbCc/, $line1), split(/AaBbCc/, $line2);
local $" = "</td><td>"; # list seperator
print "<tr><td>@fields</td></tr>\n";

または、名前付き配列なし:

chomp($line1, $line2);
local $" = "</td><td>";
print "<tr><td>@{[split(/AaBbCc/, $line1), split(/AaBbCc/, $line2)]}</td></tr>\n";

私がしていないのは、手動でインデックスを計算したり、ループを展開したりすることです。

これらのバリアントがより高速に実行されることは保証されていませんが、実験する材料がいくつかあります。コードを本当に最適化するには、Devel::NYTProfプロファイラーを使用する必要があります。各ステートメントが実行された回数と、これにかかった平均時間を示す、非常に詳細な行ごとのレポートが作成されます。


どのフィールドにもタブが含まれていないと仮定すると、これはデータを適切なタブ区切りの出力に変換するスクリプトです。

#!/usr/bin/perl
use strict; use warnings; use feature 'say';

# usage perl convert.pl filenames...

for my $filename (@ARGV) {
  open my $oldfile, "<", $filename       or die qq(Can't open "$filename": $!);
  open my $newfile, ">", "$filename.new" or die qq(Can't open "$filename.new": $!);
  until (eof $oldfile) {
     my $line1 = <$oldfile> // die qq(unexpected eof in "$filename");
     my $line2 = <$oldfile> // die qq(unexpected eof in "$filename": uneven number of lines);
     chomp( $line1, $line2 );
     my @fields = map {split /AaBbCc/, $_, 4} $line1, $line2;
     say $newfile join "\t" => @fields;
  }
  rename $filename       => "$filename.bak" or die qq(Can't back up "$filename");
  rename "$filename.new" => $filename       or die qq(Can't replace "$filename" with transformed data);
}
于 2013-01-18T17:47:58.437 に答える