-2

ファイルを配列に格納するプロセスがあります。残念ながら、ファイルが大きすぎる場合 (たとえば 800K 行または 60 MB 以上)、"メモリ不足!" のようなエラーが返されます。これに対する解決策はありますか?たとえば、次のコードは「メモリ不足です!」をスローします。

#! /usr/bin/perl

die unless (open (INPUT, "input.txt"));
@file=<INPUT>;                     # It fails here 
print "File stored in array\n";    # It never reaches here
$idx=0;
while ($idx < @file) {
    $idx++;
}
print "The line count is = $idx\n";
4

2 に答える 2

2

ほとんどの場合、ファイル全体を一度に読み込む必要はありません。readline 演算子は、スカラー コンテキストで呼び出された場合、一度に 1 行だけを返します。

1 while <INPUT>;   # read a line, and discard it.
say "The line count is = $.";

$.特殊変数は、最後に読み取られたファイルハンドルの行番号です。


編集:行数は単なる例です

Perl は大きな配列に問題はありません。システムに十分なメモリがないようです。Perl 配列は C 配列よりも多くのメモリを使用することに注意してください。これは、スカラーがフラグなどに追加のメモリを割り当てるためであり、配列は段階的に増加するためです。

メモリが問題になる場合は、ファイル全体をメモリにロードする必要があるアルゴリズムから、一度に 1 行だけ保持するアルゴリズムに変換する必要があります。

例: 数ギガバイトのファイルのソート。ここでは、通常のアプローチprint sort <$file>は機能しません。代わりに、ファイルの一部を並べ替えて一時ファイルに書き込み、巧妙な方法で一時ファイルを切り替えて、1 つの並べ替えられた出力を生成します。

use strict; use warnings; use autodie;

my $blocksize = shift @ARGV; # take lines per tempfile as command line arg

mkdir "/tmp/$$";  # $$ is the process ID variable

my $tempcounter = 0;
my @buffer;
my $save_buffer = sub {
    $tempcounter++;
    open my $tempfile, ">", "/tmp/$$/$tempcounter";
    print $tempfile sort @buffer;
    @buffer = ();
};
while (<>) {
  push @buffer, $_;
  $save_buffer->() if $. % $blocksize == 0;
}
$save_buffer->();

# open all files, read 1st line
my @head =
  grep { defined $_->[0] }
  map { open my $fh, "<", $_; [scalar(<$fh>), $fh] }
  glob "/tmp/$$/*";

# sort the line-file pairs, pick least
while((my $least, @head) = sort { $a->[0] cmp $b->[0] } @head){
  my ($line, $fh) = @$least; print $line;

  # read next line
  if (defined($line = <$fh>)){
    push @head, [$line, $fh];
  }           
}

# clean up afterwards
END {
  unlink $_ for glob "/tmp/$$/*";
  rmdir "/tmp/$$";
}

のように呼び出すことができます$ ./sort-large-file 10000 multi-gig-file.txt >sorted.txt

この一般的なアプローチは、あらゆる種類の問題に適用できます。これは「分割統治」戦略です。問題が大きすぎる場合は、小さな問題を解決してから、断片を結合します。

于 2013-06-19T22:55:46.940 に答える