最適化の第 1 のルールは、早すぎないことです (つまり、コードをプロファイリングせずに時期尚早の結論に飛びつくことです)。
2 番目のルールは、おそらくキャッシングに関するものです。
あなたのFile2
はあまり大きくありません。それをメモリにロードすると思います。これには次の利点があります。
- 解析は一度だけ行います。
- ファイルはそれほど大きくないので、スペースはそれほど問題になりません。
- 検索を非常に簡単にするデータ構造を作成できます。
その最初のポイントについて: 各行を 3,000 回以上分割します。それらのサイクルは、よりよく費やされた可能性があります。
その 3 番目のポイントについて: インデックス変換を行っているようです:
1 → 1, 2 → 2, 0 → 3
if/elsif スイッチ (線形の複雑さ) を使用してすべての値をテストする代わりに、この変換 (一定時間のルックアップ) を行う配列を使用できます。
my @conversion = (3, 1, 2);
...;
print OUT $value[$conversion[$data[$RS++]]];
このインデックス変換が一定である場合、解析時に一度だけ行うことができますFile2
。これは次のようになります
use strict; use warnings;
use autodie; # automatic error handling
my @file2;
{
open my $file2, "<", "File2.txt";
while (<$file2>) {
my (undef, @vals) = split;
# do the reordering. This is equivalent to @vals = @vals[2, 0, 1];
unshift @vals, pop @vals;
push @file2, \@vals;
}
}
これで、 の繰り返しに進むことができますFile1
。File2
今から対応するエントリを印刷すると、次のようになります
open my $file1, "<", "File1.txt";
<$file1>; # remove header
while (<$file1>) {
my ($id, @indices) = split;
print $id, map $file2[$_][$indices[$_]], 0 .. $#indices;
# but I guess you'd want some separator in between
# If so, set the $, variable
}
このアルゴリズムは依然として 2 次 (変装しmap
た - ループにすぎません) ですが、これにはより優れた定数係数が必要です。for
入力例を指定した上記のコードの出力は次のとおりです。
23 A F G
34 B E I
45 A D I
23 C F H
10 B D G
(付き$, = " "; $\ = "\n"
)。
ここからどこへ
この最後のステップ (File1 のループ処理)は並列化できますが、あまり役に立たない可能性があります。IO は遅く、スレッド間の通信は高価であり (IPC はさらに高価です)、出力はランダムな順序になります。多数のワーカーを生成し、未解析の行をキューに渡すことができます。
use threads; # should be 1st module to be loaded
use Thread::Queue;
use constant NUM_THREADS => 4; # number of cores
# parse the File2 data here
my $queue = Thread::Queue->new;
my @threads = map threads->new(\&worker), 1 .. NUM_THREADS;
# enqueue data
$queue->enqueue($_) while <$file1>;
# end the queue
$queue->enqueue((undef) x NUM_THREADS); # $queue->end in never versions
# wait for threads to complete
$_->join for @threads;
sub worker {
while(defined(my $_ = $queue->dequeue)) {
my ($id, @indices) = split;
print $id, map $file2[$_][$indices[$_]], 0 .. $#indices;
}
}
@file2
これにより、がすべてのスレッドにコピーされることに注意してください。興味深い事実: サンプル データの場合、このスレッド化されたソリューションには約 4 倍の時間がかかります。これは主にスレッド作成のオーバーヘッドであるため、データにとってはそれほど問題になりません。
いずれにせよ、コードをプロファイリングして、最も効果的に最適化できる場所を確認してください。私は優秀をお勧めしDevel::NYTProf
ます。たとえば、この非常に限られたデータを使用したスレッド化されていないテストの実行ではautodie
、実際の処理を行うよりも多くの時間を費やした友人が暗示するオーバーヘッドがありました。あなたにとって、最も高価な回線はおそらく
print $id, map $file2[$_][$indices[$_]], 0 .. $#indices;
しかし、Perl 内部でできることはあまりありません。