Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database 为什么我的Perl脚本会出现“内存不足”异常?_Database_Perl_Memory - Fatal编程技术网

Database 为什么我的Perl脚本会出现“内存不足”异常?

Database 为什么我的Perl脚本会出现“内存不足”异常?,database,perl,memory,Database,Perl,Memory,我需要逐行读取一个200mb空间分隔的文件,并将其内容收集到一个数组中 每次我运行脚本时,Perl都会抛出内存不足异常,但我不明白为什么 请给我一些建议好吗 #!/usr/bin/perl -w use strict; use warnings; open my $fh, "<", "../cnai_all.csd"; my @parse = (); while (<$fh>) { my @words = split(/\s/,$_); push (@p

我需要逐行读取一个200mb空间分隔的文件,并将其内容收集到一个数组中

每次我运行脚本时,Perl都会抛出内存不足异常,但我不明白为什么

请给我一些建议好吗

#!/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;
上面的代码只是一个简单的示例。最终的脚本将把所有值存储在一个散列中,并在以后将其写入数据库


但首先,我必须解决记忆问题

您的while循环不会从文件中读取。你应该


或者括号里的东西。

那是因为。。。你的内存快用完了

您不仅仅存储了200MB的数据。您正在为每一行创建一个新的列表数据结构及其所有相关开销,还为每个单词创建一组单独的字符串对象及其所有相关开销

编辑:作为我们在这里讨论的开销类型的一个示例,每个值都包括字符串:


因此,每个Perl对象至少有4个32位的值。

通常这意味着Perl的内存不足,但也有可能没有耗尽系统内存。首先,有一些方法可以让您在中获得有关perl内存使用情况的更多信息,尽管您可能会发现自己正在重新编译perl。还要注意文档中关于perl对内存的渴求的警告

然而,在许多操作系统中,内存限制可以按进程或用户设置。例如,如果您正在使用Linux或其他POSIX系统,则可能需要修改ulimit。输入'ulimit-a'并查看您的内存大小;您的“最大内存大小”可能低于计算机内存,或者您的数据段大小有限。然后可以使用适当的选项重置它,例如ulimit-d 1048576,用于1GB数据段大小限制


当然,还有另一种选择:如果您的情况允许,逐行处理文件。上面的示例代码可以这样重写。

您正在使用的数据库可能具有批量导入功能。我会先试试

如果在将每一行放入数据库之前需要对其执行某些操作(假设操作不需要引用其他行),则应在处理完成后立即将该行插入数据库关闭自动提交,而不是尝试将所有数据存储在内存中


如果每行的处理取决于其他行中的信息,则可以使用将输入文件视为一个行数组。同样,不要试图在内存中存储每行的内容。处理完成后,将其发送到数据库。

不要一次读取core中的所有46200000值,您在cnai_all.csd中对数据的描述为有多行,这表明每行都可以独立处理。如果是,请使用

while (<$fh>) {
  my @words = split /\s/, $_;
  insert_row \@words;
}
但是如果字段之间有多个空格呢?这是指一个空字段还是一个宽分隔符

DB<2> x split /\s/, "foo bar baz" 0 'foo' 1 '' 2 'bar' 3 'baz'
最后,我找到了一个更适合我的问题的解决方案:

在对我不得不开发的其他解析器进行一些研究之后,我学会了 关于模块DBD::CSV

CSV允许我从>4000个空格分隔的字段中只选择所需的列。这减少了内存使用,性能也很好

更多

多亏了gbacon,我改变了我的策略,从一次阅读整个文件到一部分一部分地阅读。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

代码说了,但它没有显示在标记中。@floppy doo请编辑您的问题,让我们了解cnai_all.csd的内容是什么样的?另请参见:如果您只需要print scalar@parse的输出行数,只需执行'my$i=0$i++while;打印$i;。那么,你有多少内存,还有什么在使用它呢但这不应该是太多的开销,是吗?除非它是一个真正的退化文件,否则如果它能使内存中的有效大小增加一倍,我会感到惊讶。这些不是列表结构。它们是数组。在大多数语言中,没有区别。在Perl中,有一个。我刚刚和floopy doo谈了一个小时,我们在同一家公司工作。事实证明,当我们不再依赖$将行从while传输到split语句时,问题就消失了。。奇怪的道蟾蜍,这种区别与手边的要点完全无关。@lexu我已经试过我的$line=$\;split/\s/,$line和while definedmy$line=但看到了相同的行为。请提供更多关于解决方法的具体信息。问题在于从某种程度上是ha的格式中提取数据,我听到过更强大的术语是复杂的逗号分隔格式。由于文件中的最后一行12'000+行4'500字段,每个字段都可以更改/增加第一行中省略的内容。因为文件的内容不存在 对于12个不同的DB表,我建议分两次检查该文件。首先分成12组,在第二阶段将每个文件收集/压缩成记录。我会仔细阅读Tie::文件,谢谢你的建议。 DB<1> x split /\s/, "foo bar baz" 0 'foo' 1 'bar' 2 'baz' DB<2> x split /\s/, "foo bar baz" 0 'foo' 1 '' 2 'bar' 3 'baz' DB<3> x split /\s/, " foo bar baz" 0 '' 1 'foo' 2 'bar' 3 'baz'
while (<$fh>) {
  insert_row [ split ];
}
#!/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 ";