Одним из простых улучшений является использование кодировки фиксированной ширины, такой как latin1
, для ускорения декодирования символов, хотя я не уверен, насколько это поможет.
Что касается механизма регулярных выражений / грамматики Ракудо, я обнаружил, что он довольно медленный, поэтому, возможно, действительно необходимо использовать более низкоуровневый подход.
Я не делал никаких тестов, но сначала попробую что-то вроде этого:
my %seqs = slurp('genome.fa', :enc<latin1>).split('>')[1..*].map: {
.[0] => .[1..*].join given .split("\n");
}
Поскольку стандартная библиотека Perl6 реализована в самом Perl6, иногда можно улучшить производительность, просто избегая ее, написав код в императивном стиле, например:
my %seqs;
my $data = slurp('genome.fa', :enc<latin1>);
my $pos = 0;
loop {
$pos = $data.index('>', $pos) // last;
my $ks = $pos + 1;
my $ke = $data.index("\n", $ks);
my $ss = $ke + 1;
my $se = $data.index('>', $ss) // $data.chars;
my @lines;
$pos = $ss;
while $pos < $se {
my $end = $data.index("\n", $pos);
@lines.push($data.substr($pos..^$end));
$pos = $end + 1
}
%seqs{$data.substr($ks..^$ke)} = @lines.join;
}
Однако, если части используемой стандартной библиотеки видели некоторую работу с производительностью, это может на самом деле ухудшить ситуацию. В этом случае следующим шагом будет добавление низкоуровневых аннотаций типа, таких как str
и int
, и замена вызовов на подпрограммы, такие как .index
, на встроенные NQP , такие как nqp::index
.
Если это все еще слишком медленно, вам не повезло, и вам нужно будет переключать языки, например, вызывать Perl5 с помощью Inline::Perl5
или C с помощью NativeCall
.
Обратите внимание, что @timotimo провел некоторые измерения производительности и написал статью об этом.
Если моя короткая версия является базовой, императивная версия повышает производительность в 2,4 раза.
Ему действительно удалось выжать 3-кратное улучшение из короткой версии, переписав его
my %seqs = slurp('genome.fa', :enc<latin-1>).split('>').skip(1).map: {
.head => .skip(1).join given .split("\n").cache;
}
Наконец, переписывание императивной версии с использованием встроенных NQP ускорило процесс в 17 раз, но, учитывая потенциальные проблемы с переносимостью, написание такого кода, как правило, не рекомендуется, но на данный момент может потребоваться, если вам действительно нужен такой уровень производительности:
use nqp;
my Mu $seqs := nqp::hash();
my str $data = slurp('genome.fa', :enc<latin1>);
my int $pos = 0;
my str @lines;
loop {
$pos = nqp::index($data, '>', $pos);
last if $pos < 0;
my int $ks = $pos + 1;
my int $ke = nqp::index($data, "\n", $ks);
my int $ss = $ke + 1;
my int $se = nqp::index($data ,'>', $ss);
if $se < 0 {
$se = nqp::chars($data);
}
$pos = $ss;
my int $end;
while $pos < $se {
$end = nqp::index($data, "\n", $pos);
nqp::push_s(@lines, nqp::substr($data, $pos, $end - $pos));
$pos = $end + 1
}
nqp::bindkey($seqs, nqp::substr($data, $ks, $ke - $ks), nqp::join("", @lines));
nqp::setelems(@lines, 0);
}