Использование потоков при анализе последовательности ДНК с помощью Perl - PullRequest
0 голосов
/ 28 октября 2018

У меня есть пример последовательности ДНК, такой как: S = ATGCGGGCGTGCTGCTGGGCTGCT.... длиной 5 МБ.Кроме того, у меня есть координаты гена для каждого гена, например:

Gene no. Start End
1          1    50
2         60    100
3         110   250
.....
4000      4640942 4641628 

Моя цель - выполнить определенный расчет для каждой начальной позиции гена.Мой код работает отлично.Тем не менее, это довольно медленно.Я просмотрел много страниц справки, чтобы ускорить его с помощью потоков, но, к сожалению, не смог понять.

Вот краткий обзор моего кода:

foreach my $gene($sequence){
     my @coordinates = split("\t",$gene);
     $model1 = substr($sequence, $coordinates[1], 50);
     $model2 = substr($sequence, $coordinates[1], 60);
     $c-value = calculate($model1, $model2);
     ....
}

sub calculate {
     ......
}

Я был бы очень признателен, если бы кто-нибудь смогподскажите как распараллелить такого рода программы.То, что я хочу распараллелить, - это вычисление значения c между model1 и model2 для каждого гена, что в конечном итоге ускорит процесс.Я пытался использовать Threads :: queue, но закончилось кучей ошибок.Я довольно новичок в программировании на Perl, поэтому любая помощь высоко ценится.

Спасибо всем за ваши комментарии и предложения.Я изменил код, и он, кажется, работает с использованием модуля Perl Parallel :: ForkManager.Код успешно использует все 4 ядра моего компьютера.

Вот модифицированный код:

    use strict;
    use warnings;
    use Data::Dumper;
    use Parallel::ForkManager;
    my $threads = 4;
    my $pm = new Parallel::ForkManager($threads);
    my $i = 1; #gene number counter
    $pm -> run_on_finish( sub { $i++; print STDERR "Checked $i genes" if ($i % $number_of_genes == 0); } ); 
    my @store_c_value = ();
    foreach my $gene($sequence){
                 my $pid = $pm->start and next;
                 my @coordinates = split("\t",$gene);
                 my $model1 = substr($sequence, $coordinates[1], 50);
                 my $model2 = substr($sequence, $coordinates[1], 60);
                 my $c-value = calculate($model1, $model2);
                 push(@store_c_value, $c-value);
                 $i++;
                 $pm->finish;
            }
    $pm->wait_all_children;
            sub calculate {
                 ......
                 return ($c-value);
            }
    print Dumper \@store_c_value;

В настоящее время я не получаю вывод для @store_c_value (т. Е. Пустой массив).Я обнаружил, что вы не можете сохранить данные из дочернего процесса в массив, который был объявлен в основной программе.Я знаю, что могу напечатать его во внешний файл, но я хочу, чтобы эти данные были в массиве @store_c_value, так как я использую их позже в программе.

Еще раз спасибо за помощь.

1 Ответ

0 голосов
/ 28 октября 2018

Один из вариантов - IO :: Async :: Function , который будет использовать вилки или потоки в зависимости от того, на какой ОС вы работаете (разветвление гораздо эффективнее в системах Unixy), и поддерживать набор рабочих.процессы / потоки для параллельного выполнения кода.Он возвращает Future экземпляров, которые можно использовать для синхронизации асинхронного кода по мере необходимости.Есть много способов использовать Future, пара из которых представлена ​​ниже.

use strict;
use warnings;
use IO::Async::Loop;
use IO::Async::Function;
use Future;

my $loop = IO::Async::Loop->new;
# additional options can be passed to the IO::Async::Function constructor to control how the workers are managed
my $function = IO::Async::Function->new(code => \&calculate);
$loop->add($function);

my @futures;
foreach my $gene($sequence){
     my @coordinates = split("\t",$gene);
     my $model1 = substr($sequence, $coordinates[1], 50);
     my $model2 = substr($sequence, $coordinates[1], 60);
     push @futures, $function->call(args => [$model1, $model2])->on_done(sub {
         my $c_value = shift;
         # further code using $c_value must be here, to be run once the calculation is done
     })->on_fail(sub {
         warn "Error in calculation for $gene: $_[0]\n";
     });
}

# wait for all calculations and on_done handlers before continuing
Future->wait_all(@futures)->await;

Если вы хотите, чтобы программа немедленно прекратилась, если в одном из вычислений есть исключение, вы можете использовать needs_all и удалить отдельное лицо.обработчики on_fail, и используйте get, который является оболочкой await, который затем вернет все значения c по порядку, если они пройдут успешно, или выдаст исключение в случае сбоя.

my @c_values = Future->needs_all(@futures)->get;
...