<> 运算符缓冲区大小

<> operator buffer size

我有一个包含很长行的文件需要处理,但我发现进程卡住了/'really slow' 因为缓冲区不够大或者处理很长的行可能需要一段时间。这是一个代码示例:

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);
}

线路处理不是"heavy"。

我正在寻找解决问题的方法并遇到了 PerlIO::buffersize,但看起来它已经有一段时间没有维护了,我不想使用版本为 0.001 的模块。如何修改 <> 运算符缓冲区大小?或者,在使用 <>?

阅读之前,有没有办法知道行的长度

可能你需要的是这个:

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

Setting $/ to a reference to an integer, scalar containing an integer, or scalar that's convertible to an integer will attempt to read records instead of lines, with the maximum record size being the referenced integer number of characters.

来源:perlvar

改变 Perl 的读取缓冲区大小不太可能对您的程序速度产生任何显着影响,您看到的影响更有可能是磁盘驱动器本身读取时间较长的结果。看看 perlmonks.org

上的 Perl Read-Ahead I/O Buffering

此外,通过使用 read 或将记录分隔符 $/ 设置为固定大小来实现您自己的缓冲很可能会减慢您的程序,因为您仍然必须将内容分开您已经读入了数据行,但现在必须用 Perl 代码来完成,而不是让 perl 在 C

中为您完成

另请注意,将 $/ 更改为固定记录大小的措施仍将使用 Perl 的标准缓冲区,可能为 8KB。唯一的区别是返回给你的数据量将根据字节数而不是分隔符字符串的位置来确定

How can I modify the <> operator buffer size?

<> 读入一个可以增长到任意大小的标量,所以我认为你指的是传递给 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

只能在构建perl时配置,使用以下命令

./Configure -Accflags=-DPERLIOBUF_DEFAULT_BUFSIZ=8192

这适用于所有缓冲读取函数,包括 readreadline<> 是别名)、readpipeeof,但不是 sysread.


请注意,将 $/ 设置为对数字的引用将导致 readline (<>) 充当 read,仍处于缓冲状态。

$ strace perl -e'$/ = 93; 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