File :: Slurp成多GB标量 - 如何高效分割?

时间:2014-02-12 17:53:31

标签: perl split fileslurp

我有一个要在Perl中处理的多GB文件。逐行读取文件需要几分钟;通过File :: Slurp将其读入标量需要几秒钟。好。现在,处理标量的每个“线”的最有效方法是什么?我想我应该避免修改标量,例如在我处理它时,每个连续的行都要删掉,以避免重新分配标量。

我试过了:

use File::Slurp;
my $file_ref = read_file( '/tmp/tom_timings/tom_timings_15998', scalar_ref => 1  ) ;

for my $line (split /\n/, $$file_ref) {
    # process line
}

这是分钟:足够但不是很好。有更快的方法吗? (我的记忆力比上帝多。)

1 个答案:

答案 0 :(得分:5)

除非你开始交换,否则

split应该非常快。我能看到加速它的唯一方法是编写一个寻找LF而不是使用正则表达式的XS函数。

顺便说一句,你可以通过切换到

来节省大量内存
while ($$file_ref =~ /\G([^\n]*\n|[^\n]+)/g) {
    my $line = $1;
    # process line
}

表示XS功能。如果您不想选择,请在newSVpvn_flags语句后移动if行。

SV* next_line(SV* buf_sv) {
    STRLEN buf_len;
    const char* buf = SvPV_force(buf_sv, buf_len);
    char* next_line_ptr;
    char* buf_end;
    SV* rv;

    if (!buf_len)
        return &PL_sv_undef;

    next_line_ptr = buf;
    buf_end = buf + buf_len;
    while (next_line_ptr != buf_end && *next_line_ptr != '\n')
        ++next_line_ptr;

    rv = newSVpvn_flags(buf, next_line_ptr-buf, SvUTF8(buf_sv) ? SVf_UTF8 : 0);

    if (next_line_ptr != buf_end)
        ++next_line_ptr;

    sv_chop(buf_sv, next_line_ptr);
    return rv;  /* Typemap will mortalize */
}

测试方法:

use strict;
use warnings;

use Inline C => <<'__EOC__';

SV* next_line(SV* buf_sv) {
    ...
}

__EOC__

my $s = <<'__EOI__';
foo
bar
baz
__EOI__

while (defined($_ = next_line($s))) {
   print "<$_>\n";
}