Чтение файла построчно в Perl6, как это сделать идиоматически? - PullRequest
7 голосов
/ 13 апреля 2019

У меня есть элементарный скрипт в Perl6, который выполняется очень медленно, примерно в 30 раз медленнее, чем точный перевод perl5.

CONTROL {
    when CX::Warn {
        note $_;
        exit 1;
    }
}
use fatal;
role KeyRequired {
    method AT-KEY (\key) {
        die "Key {key} not found" unless self.EXISTS-KEY(key);
        nextsame;
    }
}

for dir(test => /^nucleotide_\d**2_\d**2..3\.tsv$/) -> $tsv {
    say $tsv;
    my $qqman = $tsv.subst(/\.tsv$/, '.qqman.tsv');
    my $out = open $qqman, :w;
    put "\t$qqman";
    my UInt $line-no = 0;
    for $tsv.lines -> $line {
        if $line-no == 0 {
            $line-no = 1;
            $out.put(['SNP', 'CHR', 'BP', 'P', 'zscore'].join("\t"));
            next
        }
        if $line ~~ /.+X/ {
            next
        }
        $line-no++;
        my @line = $line.split(/\s+/);
        my $chr = @line[0];
        my $nuc = @line[1];
        my $p = @line[3];
        my $zscore = @line[2];
        my $snp = "'rs$line-no'";
        $out.put([$snp, $chr, $nuc, $p, $zscore].join("\t"));
        #$out.put();
    }
    last
}

это идиоматично в Perl5 while.

Это очень простой скрипт, который изменяет только столбцы текста в файле.Этот скрипт Perl6 выполняется за 30 минут.Перевод Perl5 выполняется за 1 минуту.

Я попытался прочитать Использование Perl6 для обработки большого текстового файла, и это слишком медленно. (2014-09) и Perl6:Каков наилучший способ работы с очень большими файлами? , но я не вижу ничего, что могло бы мне здесь помочь: (

Я бегу Rakudo version 2018.03 built on MoarVM version 2018.03 implementing Perl 6.c.

Я понимаю,что Ракудо еще не достиг уровня Perl5 (пока, я надеюсь), но как я могу заставить это читать файл построчно в более разумные сроки?

1 Ответ

10 голосов
/ 13 апреля 2019

Я бы изменил кучу вещей.

  • /.+X/ можно упростить до /.X/ или даже $line.substr(1).contains('X')
  • $line.split(/\s+/) можно упростить до $line.words
  • $tsv.subst(/\.tsv$/, '.qqman.tsv') можно упростить до $tsv.substr(*-4) ~ '.qqman.tsv'
  • uint вместо UInt
  • given .head {} вместо for … {last}
given dir(test => /^nucleotide_\d**2_\d**2..3\.tsv$/).head -> $tsv {
    say $tsv;
    my $qqman = $tsv.substr(*-4) ~ '.qqman.tsv';
    my $out = open $qqman, :w;
    put "\t$qqman";

    my uint $line-no = 0;
    for $tsv.lines -> $line {
        FIRST {
            $line-no = 1;
            $out.put(('SNP', 'CHR', 'BP', 'P', 'zscore').join("\t"));
            next
        }
        next if $line.substr(1).contains('X');

        ++$line-no;

        my ($chr,$nuc,$zscore,$p) = $line.words;

        my $snp = "'rs$line-no'";
        $out.put(($snp, $chr, $nuc, $p, $zscore).join("\t"));
        #$out.put();
    }
}
...