【问题标题】:<> operator buffer size<> 操作符缓冲区大小
【发布时间】:2016-08-17 07:26:16
【问题描述】:

我有一个需要处理的行很长的文件,我发现该过程卡住/“真的很慢”,因为缓冲区不够大,或者由于处理很长的行可能需要尽管。这是一个代码示例:

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 的模块。如何修改&lt;&gt; 运算符缓冲区大小?或者,在使用&lt;&gt; 阅读之前,有什么方法可以知道行长?

【问题讨论】:

  • 嗯,您也可以将$/ 设置为要读取的字节数的数值。
  • 您可以转到比readline (&lt;&gt;) 更低的级别并使用readFile::Stream 也可能有帮助。
  • @yonyon100:请告诉我们“非常长的行”的长度和文件的总大小。
  • my @arr = split //, $_; 一次遍历你的字符串一个字符,所以是的,长行需要一段时间。这就是为什么you should always explain your actual problem instead of the solution you think will work;你找错树了!
  • 我认为您应该发布一个新问题并解释您要解决的实际问题,并附上示例输入和输出。展示您当前的解决方案并说明您的性能要求,例如“我想在 30 秒内处理一个 20MB 的单行文件。”

标签: perl buffer file-handling


【解决方案1】:

可能你需要的是这样的:

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

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

来源:perlvar

【讨论】:

  • 这不会改变 Perl 的内部缓冲区大小,但这不太可能成为问题。
  • OP 仍然希望以行的形式读取数据,因此当您将行组装从 C 移动到 Perl 时,这实际上会使事情变慢。
【解决方案2】:

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

上的 Perl Read-Ahead I/O Buffering

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

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

【讨论】:

    【解决方案3】:

    如何修改&lt;&gt; 操作符缓冲区大小?

    &lt;&gt; 读入一个可以增长到任意大小的标量,所以我认为您指的是传递给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&lt;&gt; 是其别名)、readpipeeof,但不适用于sysread


    请注意,将$/ 设置为对数字的引用将导致readline (&lt;&gt;) 充当read,该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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-14
      • 2020-09-05
      • 2014-06-10
      • 1970-01-01
      • 2015-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多