コードが遅い理由はいくつかあります。
- 使用されているファイル形式は頭がおかしいです。
で検索するすべての要素@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
コードのパフォーマンスを向上させるためのベスト プラクティスがいくつかあります。たとえば、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);
}