スクリプトのパフォーマンスのボトルネックは、メモリの使用ではなく、レコードごとにファイルを開いたり閉じたりすることだと思います。単位を正しく理解していれば、10lakh は 1,000,000 です。
1 つの解決策は、データをバッチで処理することです。特に、キーとして抽出する「最初の 5」に多くのキーが繰り返される場合はそうです。
その 2 番目のフィールドに 100 個の一意の 5 桁のキーを含むが、10,000,000 レコード (ファイルのサイズの 10 倍) を含む合成ファイルで、以下のプログラムに対してあなたのプログラムをベンチマークしました。行は次のようになりました。
1,9990001,----------------------------------------------------------------------------------------------------
2,9990002,----------------------------------------------------------------------------------------------------
3,9990003,----------------------------------------------------------------------------------------------------
これは、入力内の適度に大量のデータをシミュレートするために行いました。入力ファイルのレコード数の約 10 倍になるはずです。
あなたの元のスクリプトは、私のコンピューターでこの入力を処理するのに 2 分以上かかりました。次のスクリプトは、10,000 レコードのバッチを使用しており、24 秒かかりました。5倍以上の速さです。
my $file = "my_csv_file.csv";
open (my $data, '<', $file) or die "Could not open '$file' $!\n";
sub write_out
{
my $batch = shift;
for my $first_five (keys %$batch)
{
my $file_name = $first_five . ".csv";
my $need_title = ! -e $file_name;
open my $fh, '>>', $file_name or die $!;
print $fh "Title\n" if $need_title;
print $fh @{ $batch->{$first_five} };
close $fh;
}
}
my ($line, $batch, $count);
$batch = { };
$count = 0;
while ($line = <$data>)
{
next if $. == 1;
if ($line =~ /^[^,]*,(.....)/)
{
push @{ $batch->{$1} }, $line;
if (++$count > 10000) # adjust as needed
{
write_out $batch;
$batch = { };
$count = 0;
}
}
}
write_out $batch if $count; # write final batch
close $data;
ここで、私のスクリプトの出力とあなたのスクリプトの出力の間に 1 つの違いがあることに気付きました。あなたのスクリプトは、出力先の .csv ファイルごとに出力の最初の行を削除しTitle
、その場所に単語を配置しているようです。エラーだったと思います。上記のスクリプトは、指定された「最初の 5 つ」の最初のインスタンスを削除せずに、 という名前の行を追加します。Title
以前の動作が必要な場合は、 で変更できますsub write_out
。
いくつかの追加実験を行いました。バッチ サイズを 10,000,000 に変更して、write_out
1 回だけ呼び出されるようにしました。メモリ使用量はかなり増加し、実行時間はわずか 22 秒になりました。また、バッチ サイズを 100 に変更してみました。メモリ使用量は劇的に減少しましたが、実行時間は約 30 秒になりました。これは、ファイルの開閉が真のボトルネックであることを示唆しています。
したがって、バッチ サイズを変更することで、実行時間に対するメモリ フットプリントを制御できます。いずれにせよ、バッチ指向のコードは、現在のアプローチよりもはるかに高速になるはずです。
編集: 2 番目の 1000 万レコード入力を使用してさらにベンチマークを行い、今回は 5 桁のキーを完全にランダム化しました。00000.csv
結果の出力は、 ~という名前の 100,000 個のファイルを書き込みます99999.csv
。元のスクリプトの実行には約 3 分かかりますが、上記のスクリプト (バッチ サイズが 1000000) は約 1:26 かかり、約 2 倍の速さです。
ボトルネックはスクリプト自体ではなく、ファイル システムの操作です。100,000 個のファイルを作成/更新するには、本質的にコストがかかります。