6

Perl で処理するマルチ GB ファイルがあります。ファイルを 1 行ずつ読み取るには数分かかります。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分未満です.十分ですが、素晴らしいとは言えません. これを行うより速い方法はありますか?(私は神よりも多くの記憶を持っています。)

4

1 に答える 1

6

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";
}
于 2014-02-12T18:22:51.563 に答える