2016-08-17 114 views
1

我有一个需要处理的非常长的行的文件,并且我发现进程被卡住/'非常慢',因为缓冲区不够大或者由于处理非常慢长线可能需要一段时间。这里是一个代码示例:<>运算符缓冲区大小

open FH, "<$fname" or die "..."; 
while (<FH>) { 
    my @arr = split //, $_; 
    pop @arr; 
    pop @arr; 
    ... for some "limited small portion of the string length" number of times ... 
    pop @arr; 
    if ($arr[-1] eq '0') { 
     print "done!\n"; 
     last; 
    } 
    push @big_arr, join('', @arr); 
} 

行处理不是“重”。

我寻找一些东西来解决它,并遇到了PerlIO::buffersize,但它看起来像它不被维护一段时间,我不想使用0.001版本的模块。我如何修改<>运算符缓冲区大小?或者,还有什么方法可以在用<>读取之前知道行长?

+0

我们在这里说话多长时间?我认为没有什么特别的原因可以解释为什么'缓冲区'大小特别成问题 - 我已经使用了这种结构和记录分隔符 - 很多'行'长 - 并且它工作得很好。你确定这是'时'循环,这会减慢你的速度吗? – Sobrique

+0

@Sobrique我不确定,但是当我将这段代码放在一个文件中的时候,它的行数很短,它的功能非常强大,并且运行速度非常快。线条很长。把它看作好像你有一个大文本文件全部打包成一行或两行(我对这些文件的格式没有任何控制权)。 – yonyon100

+0

但你确实有能力设置'$ /' - 记录分隔符。有什么合适的,你可以'分裂'线? – Sobrique

回答

3

这可能是你所需要的是这样的:

$/ - 可以设置为一个数值,对于字节数从文件中读取。

将$ /设置为对整数,包含整数的标量或可转换为整数的标量的引用将尝试读取记录而不是行,最大记录大小为引用的整数字符数。

来源:perlvar

+2

这不会改变Perl的内部缓冲区大小,但这不太可能成为问题。 – Borodin

+1

OP仍然希望以行的形式读取数据,因此当您将从C组装到Perl的行移动时,实际上它会使事情稍微慢一些。 – ikegami

3

涂改Perl的读取缓冲区的大小是不可能让你的程序的速度没有任何显著差异,您所看到的影响更可能是在较长的读取结果从磁盘驱动器本身的时间。拿上一看Perl Read-Ahead I/O Bufferingperlmonks.org

此外,通过使用read或记录分隔$/设置为一个固定大小的实现自己的缓冲,极有可能对你的程序慢下来更多,因为你还是要把你读到的数据分成几行数据,但现在必须用Perl代码来代替,而不是让perl为你做C

请注意,将$/更改为固定记录大小的措施仍将使用Perl的标准,大概8KB,缓冲区。唯一的区别是,数据量交还给你将按照字节数,而不是分隔字符串

1

我如何修改<>操作缓冲区大小的位置来确定?

<>读入,可以长到任意大小的标,所以我想你指的是传递给read系统调用的缓冲区的大小。

在5.14之前,Perl从4个KiB块中读取文件句柄。 5.14使这种配置成为可能,默认值为8 KiB。

$ perl -e'print("x" x 9_999, "\n") for 1..2' >large_lines 

$ strace 5.10.1t/bin/perl -e'my $line = <>' large_lines 2>&1 | grep read.*xxx 
read(3, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096 
read(3, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096 
read(3, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096 

$ strace 5.14.2t/bin/perl -e'my $line = <>' large_lines 2>&1 | grep read.*xxx 
read(3, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 8192) = 8192 
read(3, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 8192) = 8192 

使用下面的命令

./Configure -Accflags=-DPERLIOBUF_DEFAULT_BUFSIZ=8192 

这适用于所有缓冲读取功能,包括readreadline(对于该<>是别名)它只能被配置为当perl构建,readpipeeof,但不是sysread


注意,设置$/到为数字的参考将导致readline<>)作为read,这仍然是进行缓冲。

$ strace perl -e'$/ = \8193; my $block = <>' large_lines 2>&1 | grep read.*xxx 
read(3, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 8192) = 8192 
read(3, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 8192) = 8192 

如果你真的要执行一个read系统调用,你需要使用sysread

$ strace perl -e'sysread(STDIN, $buf, 8193)' <large_lines 2>&1 | grep read.*xxx 
read(0, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 8193) = 8193