1. ホーム
  2. database

[解決済み] なぜ私のPerlスクリプトは "out of memory "例外で死んでしまうのですか?

2022-02-17 20:13:04

質問

200MBのquot;space"で区切られたファイルを一行ずつ読み込んで、その内容を配列に収集する必要があります。

スクリプトを実行するたびに、Perl は "out of memory" 例外をスローしますが、その理由がわかりません!

何かアドバイスがあればお願いします。

#!/usr/bin/perl -w
use strict;
use warnings;

open my $fh, "<", "../cnai_all.csd";
my @parse = ();

while (<$fh>) {
     my @words = split(/\s/,$_);
     push (@parse, \@words);
}

print scalar @parse;

cnaiファイルは次のようなものです:11000行と4200個の値があり、1行は"space"で区切られています。

VALUE_GROUP_A VALUE_GROUP_B VALUE_GROUP_C 
VALUE_GROUP_A VALUE_GROUP_B VALUE_GROUP_C 
VALUE_GROUP_A VALUE_GROUP_B VALUE_GROUP_C 
VALUE_GROUP_A VALUE_GROUP_B VALUE_GROUP_C 

上のコードは、あくまでも削ぎ落としたサンプルです。
最後のスクリプトは、すべての値をハッシュに格納し、後でデータベースに書き込みます。

でもその前に、メモリの問題を解決しないとね!

どのように解決するのか?

ようやく、私の問題に対するより適切な解決策を見つけました。

他のパーサーを開発するために調べた結果、私は モジュールについて DBD::CSV .

DBD::CSVでは、quot;whitespace"で区切られたフィールドの中から必要な列だけを(>4000の中から)選択することができます。これは、メモリ使用量を削減し、非常によく実行されます。

詳細はこちら DBD-CSV @ CPAN.org

gbaconさんのおかげで、ファイル全体を一度に読むのではなく、部分的に読むようにしました。DBD::CSVは、多くのコーディングなしでこれを可能にしてくれます。

#!/usr/bin/perl  -w

use strict;
use warnings;
use DBI;
## -------------------------------------------------------------------------##

## -------------------------------------------------------------------------##
## SET GLOBAL CONFIG #############
my $globalConfig = {
                _DIR => qq{../Data},
                _FILES => {
                    'cnai_all.csd'   => '_TEST'
                    }               
                };
## -------------------------------------------------------------------------##


## -------------------------------------------------------------------------##
my $sTime = time();

my $sepChar = " ";
my $csv_dbh = DBI->connect("DBI:CSV:f_dir=".$globalConfig->{_DIR}.";");

$csv_dbh->{csv_eol} ="\n";
#$csv_dbh->{csv_quote_char} ="'";
#$csv_dbh->{csv_escape_char} ="\\";
$csv_dbh->{csv_null} = 1;
$csv_dbh->{csv_quote_char} = '"';
$csv_dbh->{csv_escape_char} = '"';
$csv_dbh->{csv_sep_char} = "$sepChar";
$csv_dbh->{csv_always_quote} = 0;
$csv_dbh->{csv_quote_space} = 0;
$csv_dbh->{csv_binary} = 0;
$csv_dbh->{csv_keep_meta_info} = 0;
$csv_dbh->{csv_allow_loose_quotes} = 0;
$csv_dbh->{csv_allow_loose_escapes} = 0;
$csv_dbh->{csv_allow_whitespace} = 0;
$csv_dbh->{csv_blank_is_undef} = 0;
$csv_dbh->{csv_empty_is_undef} = 0;
$csv_dbh->{csv_verbatim} = 0;
$csv_dbh->{csv_auto_diag} = 0;


my @list = $csv_dbh->func('list_tables');
my $sth = $csv_dbh->prepare("SELECT CELL,NW,BSC,n_cell_0 FROM cnai_all.tmp");


#print join ("\n",@list);

print "\n-------------------\n";

$sth->execute();
while (my $row = $sth->fetchrow_hashref) {
    # just print a hash refrence
    print "$row\n";
}
$sth->finish();

print "\n finish after ".(time()-$sTime)." sec ";


私のマシンでは、これはおよそ20秒で実行され、10MB以上のメモリを使用しません。