我有一个巨大的文件(接近50GB,只是一个由360K行组成的ASCII矩阵,每行有15K个数字),我需要转置它。为了避免在内存中读取整个内容,我只编写了一个打开15K文件的Perl脚本(矩阵的每一列一个),然后读取输入文件的完整行,并将每个数字写入其结尾相应的文件(输出文件column0.txt的第一个数字,输出文件column1.txt的第二个数字等)。
事情看起来很有希望:代码只使用一个178MB的常量RAM,并且只有部分输入文件的初始测试运行得很好:它在大约一分钟内处理了3600行,所以我希望能完成整个过程大约两个小时,但是当我运行真实的东西时,代码会在许多点停止。例如,在开始时它很快就处理了~4600行,然后停止了很长一段时间(可能是5-10分钟),然后再继续。现在,经过大约10个小时的计算,它处理了131K行,处理300-400行后代码停止了2-3分钟。
我从未使用过这么大的输入文件或打开过多的文件,所以我不确定问题是输入还是文件描述符的数量。关于如何诊断(并希望)解决速度问题的任何建议?我在下面列出了该计划的相关部分
由于
==================================
for ($i=0 ; $i<$columnas ; $i++) {
$column[$i] = IO::File->new(">column$i.txt") or die $!;
}
while (<DATA>) {
chomp;
$cols = split;
for ($col=0 ; $col<$cols ; $col++) {
print { $column[$col] } "$_[$col] " ;
}
}
close (DATA) or die $!;
答案 0 :(得分:1)
检查/ proc / sys / fs / file-max以查看最大打开文件数 您可能需要使用搜索来阅读文件,以便您可以相应地控制打开文件的数量 最好的做法是缓存x行,然后附加到所有文件。
答案 1 :(得分:1)
一些想法
<强> 1。隐式拆分为@_
$cols = split;
发出警告:
Use of implicit split to @_ is deprecated
如果你还没有这样做,你应该添加
use warnings;
use strict;
到您的脚本。 (注意那些警告。)
考虑将$cols
更改为@cols
,而在for循环中使用$#cols
。 E.g。
@cols = split;
for (my $col=0; $col <= $#cols; $col++)
<强> 2。不需要chomp?
来自split()
中的perlfunc
:
如果也省略了PATTERN,则拆分 空白(跳过任何领先之后) 空白)。
这意味着您的换行符也应该被删除,因为它被视为空格字符。
因此,chomp()
不是必需的。
第3。打开文件数
我相信perl的open()
相当快,所以像weismat建议的那样,可能值得缓存你的数据。在执行此操作时,您可以共享所有文件的单个文件句柄,并仅在打印缓存时打开它们。 E.g:
for ($i = 0; $i <= $#column; $i++) {
open OUT, ">> column$i.txt" or die $!;
print OUT $column[$i];
}
ETA:@column
此处包含从DATA转置的列。而不是打印,使用:
$column[$col] .= $cols[$col] . " ";
答案 2 :(得分:0)
鉴于你得到了奇怪的东西,检查你的打印成功可能是一个好主意:
print { $column[$col] } "$_[$col] "
or die "Error printing column $col: $! ";
尝试冲洗每500行左右? use IO::Handle;
并在印刷之后:
if ( $. % 500 == 0 ) {
$column[$col]->flush()
or die "Flush of column $col failed: $! ";
}