преобразование версии с собственными целочисленными значениями для использования операций nqp (кстати, они официально не поддерживаются, код, использующий эти операции, может самопроизвольно прерываться при изменении rakudo), завершает работу программы всего за 2,9 с, из которых 0,34 с - системное время в зависимости от времени, и профилировщик оценивает около 18% от общего времени, затрачиваемого на саму «выпадение». Звучит ужасно плохо.

ошлой неделе я решил попробовать Perl6 и начал переопределять одну из моих программ. Должен сказать, что Perl6 настолько прост для объектного программирования, что очень болезненно для меня в Perl5.

Моя программа должна читать и хранить большие файлы, такие как целые геномы (до 3 Гб и более, см. Пример 1 ниже) или табличные данные.

Первая версия кода была сделана способом Perl5 путем итерации построчно ("genome.fa" .IO.lines). Это было очень медленно и нестабильно для правильного времени выполнения.

my class fasta {
  has Str $.file is required;
  has %!seq;

  submethod TWEAK() {
    my $id;
    my $s;

    for $!file.IO.lines -> $line {
      if $line ~~ /^\>/ {
        say $id;
        if $id.defined {
          %!seq{$id} = sequence.new(id => $id, seq => $s);
        }
        my $l = $line;
        $l ~~ s:g/^\>//;
        $id = $l;
        $s = "";
      }
      else {
        $s ~= $line;
      }
    }
    %!seq{$id} = sequence.new(id => $id, seq => $s);
  }
}


sub MAIN()
{
    my $f = fasta.new(file => "genome.fa");
}

Поэтому после небольшого RTFM я изменил на ошибку в файле, разделение на \ n, которое я проанализировал с помощью цикла for. Таким образом мне удалось загрузить данные за 2 мин. Намного лучше, но недостаточно. Обманывая, я имею в виду, удалив максимум \ n (Пример 2), я сократил время выполнения до 30 секунд. Неплохо, но не полностью удовлетворено, этот формат не является наиболее используемым.

my class fasta {
  has Str $.file is required;
  has %!seq;

  submethod TWEAK() {
    my $id;
    my $s;

    say "Slurping ...";
    my $f = $!file.IO.slurp;

    say "Spliting file ...";
    my @lines = $f.split(/\n/);

    say "Parsing lines ...";
    for @lines -> $line {
      if $line !~~ /^\>/ {
          $s ~= $line;
      }
      else {
        say $id;
        if $id.defined {
          %!seq{$id} = seq.new(id => $id, seq => $s);
        }
        $id = $line;
        $id ~~ s:g/^\>//;
        $s = "";
      }
    }
    %!seq{$id} = seq.new(id => $id, seq => $s);
  }
}

sub MAIN()
{
    my $f = fasta.new(file => "genome.fa");
}

Итак, RTFM снова и я обнаружил магию грамматики. Итак, новая версия и время выполнения 45 секунд, независимо от используемого формата fastta. Не самый быстрый способ, но более элегантный и стабильный.

my grammar fastaGrammar {
  token TOP { <fasta>+ }

  token fasta   {<.ws><header><seq> }
  token header  { <sup><id>\n }
  token sup     { '>' }
  token id      { <[\d\w]>+ }
  token seq     { [<[ACGTNacgtn]>+\n]+ }

}

my class fastaActions {
  method TOP ($/){
    my @seqArray;

    for 
my grammar fastaGrammar {
  token TOP { <fasta>+ }

  token fasta   {<.ws><header><seq> }
  token header  { <sup><id>\n }
  token sup     { '>' }
  token id      { <[\d\w]>+ }
  token seq     { [<[ACGTNacgtn]>+\n]+ }

}

my class fastaActions {
  method TOP ($/){
    my @seqArray;

    for $<fasta> -> $f {
      @seqArray.push: seq.new(id => $f.<header><id>.made, seq => $f<seq>.made);
    }
    make @seqArray;
  }

  method fasta ($/) { make ~$/; }
  method id    ($/) { make ~$/; }
  method seq   ($/) { make $/.subst("\n", "", :g); }

}

my class fasta {
  has Str $.file is required;
  has %seq;

  submethod TWEAK() {

    say "=> Slurping ...";
    my $f = $!file.IO.slurp;

    say "=> Grammaring ...";
    my @seqArray = fastaGrammar.parse($f, actions => fastaActions).made;

    say "=> Storing data ...";
    for @seqArray -> $s {
      %!seq{$s.id} = $s;
    }
  }
}

sub MAIN()
{
    my $f = fasta.new(file => "genome.fa");
}
lt;fasta> -> $f { @seqArray.push: seq.new(id => $f.<header><id>.made, seq => $f<seq>.made); } make @seqArray; } method fasta ($/) { make ~$/; } method id ($/) { make ~$/; } method seq ($/) { make $/.subst("\n", "", :g); } } my class fasta { has Str $.file is required; has %seq; submethod TWEAK() { say "=> Slurping ..."; my $f = $!file.IO.slurp; say "=> Grammaring ..."; my @seqArray = fastaGrammar.parse($f, actions => fastaActions).made; say "=> Storing data ..."; for @seqArray -> $s { %!seq{$s.id} = $s; } } } sub MAIN() { my $f = fasta.new(file => "genome.fa"); }

Я думаю, что нашел хорошее решение для обработки таких больших файлов, но производительность все еще ниже, чем у Perl5.

Будучи новичком в Perl6, мне было бы интересно узнать, есть ли лучшие способы работы с большими данными или есть какие-то ограничения из-за реализации Perl6?

Будучи новичком в Perl6, я задавал два вопроса:

Существуют ли другие механизмы Perl6, которые я еще не знаю или еще не документировал для хранения огромных данных из файла (например, мои геномы)?Достигли ли я максимальных характеристик для текущей версии Perl6?

Спасибо за чтение !

Фаста Пример 1:

>2L
CGACAATGCACGACAGAGGAAGCAGAACAGATATTTAGATTGCCTCTCATTTTCTCTCCCATATTATAGGGAGAAATATG
ATCGCGTATGCGAGAGTAGTGCCAACATATTGTGCTCTTTGATTTTTTGGCAACCCAAAATGGTGGCGGATGAACGAGAT
...
>3R
CGACAATGCACGACAGAGGAAGCAGAACAGATATTTAGATTGCCTCTCATTTTCTCTCCCATATTATAGGGAGAAATATG
ATCGCGTATGCGAGAGTAGTGCCAACATATTGTGCTCTTTGATTTTTTGGCAACCCAAAATGGTGGCGGATGAACGAGAT
...

Фаста пример 2:

>2L
GACAATGCACGACAGAGGAAGCAGAACAGATATTTAGATTGCCTCTCAT...            
>3R
TAGGGAGAAATATGATCGCGTATGCGAGAGTAGTGCCAACATATTGTGCT...

РЕДАКТИРОВАТЬ Я применил советы @Christoph и @timotimo и протестировал с помощью кода:

my class fasta {
  has Str $.file is required;
  has %!seq;

  submethod TWEAK() {
    say "=> Slurping / Parsing / Storing ...";
    %!seq = slurp($!file, :enc<latin1>).split('>').skip(1).map: {
  .head => seq.new(id => .head, seq => .skip(1).join) given .split("\n").cache;
    }
  }
}


sub MAIN()
{
    my $f = fasta.new(file => "genome.fa");
}

Программа закончилась в 2.7s, что так здорово! Я также попробовал этот код на геноме пшеницы (10 Гб). Это закончилось в 35.2 с. Perl6 не такой медленный, наконец!

Большое спасибо за помощь!

Ответы на вопрос(1)

Ваш ответ на вопрос