如何将多线程应用于Bio :: SeqIO转换代码(Bioperl)?

时间:2018-11-12 07:30:21

标签: multithreading perl bioperl

我正在通过此代码将Fasta核苷酸文件翻译成蛋白质序列

use Bio::SeqIO;
use Getopt::Long;

my ($format,$outfile) = 'fasta';

GetOptions(
    'f|format:s'  => \$format,
    'o|out|outfile:s' => \$outfile,
    );

my $oformat = 'fasta';
$file=$ARGV[0];
chomp $file;

# this implicity uses the <> file stream
my $seqin = Bio::SeqIO->new( -format => $format, -fh => \*ARGV);
my $seqout;
if( $outfile ) {
    $seqout = Bio::SeqIO->new( -format => $oformat, -file => ">$outfile" );
} else {
# defaults to writing to STDOUT
    $seqout = Bio::SeqIO->new( -format => $oformat );
}

    while( (my $seq = $seqin->next_seq()) ) {
            my $pseq = $seq->translate();
            $seqout->write_seq($pseq);
    }

我实施 线程 threads :: shared perl模块可以在其他情况下实现,但我想将以下代码应用于上一个任务

use threads;
use threads::shared;
use List::Util qw( sum );
use YAML;
use constant NUM_THREADS =>100;

my @output :shared;

my $chunk_size = @data / NUM_THREADS;

my @threads;
for my $chunk ( 1 .. NUM_THREADS ) {
    my $start = ($chunk - 1) * $chunk_size;
    push @threads, threads->create(
        \&doOperation,
        \@data,
        $start,
        ($start + $chunk_size - 1),
        \@output,
    );
}
$_->join for @threads;

sub doOperation{
    my ($data, $start, $end, $output) = @_;

    my $id = threads->tid;

    print "$id ";

    for my $i ($start .. $end) {
        print "Thread [$id] processing row $i\n";

#应该被多重理解

    while( (my $seq = $seqin->next_seq()) ) {
            my $pseq = $seq->translate();
            $seqout->write_seq($pseq);
    }

#应该被多重理解

        sleep 1 if 0.2 > rand;
    }
    print "Thread done.\n";
    return;
}
print "\n$time\n";
my $time = localtime;
print "$time\n";

正在创建线程,但是由于某种原因它无法处理fasta文件。 fisrt代码可以在没有多线程的情况下正常工作。

1 个答案:

答案 0 :(得分:2)

恐怕我不会为您重写代码,但是我可以为您提供一些有关如何完成线程化的指导。

关于perl线程,您需要了解的事情是不是轻量级线程。您应该产生与并行度相等的多个线程,将它们从Thread::Queue处运行,然后从那里去。

您还需要避免使用任何非线程安全的模块-如果您对谨慎,可以使用它们,但这通常意味着使用require和{{ 1}},而不是程序开始时的import

我还建议避免尝试并行执行输出IO-返回线程结果并在“主”线程中合并它们(如有必要,进行排序)(或分离一个编写器)。

所以我会选择类似的东西

use

注意-这无法按原样工作,因为它缺少与其余的ocde合并的功能。但是希望它能说明队列和线程如何工作以获取并行性?

您可以使用Storable中的#!/usr/bin/env perl use strict; use warnings; use threads; use Thread::Queue; use Storable qw ( freeze thaw ); my $NUM_THREADS = 16; #approx number of cores. my $translate_q = Thread::Queue->new; my $translate_results_q = Thread::Queue->new; sub translate_thread { while ( my $item = translate_q->dequeue ) { my $seq = thaw $item; my $pseq = $seq->translate(); $translate_results_q->enqueue( freeze $pseq ); } } threads->create( \&translate_thread ) for 1 .. $NUM_THREADS; while ( my $seq => $seqin->next_seq ) { $translate_q->enqueue( freeze($seq) ); } $translate_q->end; $_->join for threads->list; $translate_results_q->end; while ( my $result = $translate_results_q->dequeue ) { my $pseg = thaw($result); } freeze来传递对象,并使用并行性对其进行解压缩。

不要太着迷于线程数量-对于主要计算工作负载(例如,没有IO),那么等于内核数量的线程数量是正确的。如果他们将阻止IO,则可以增加这个数字,但是超过两倍几乎没有多大作用。

您不能真正有效地并行化磁盘IO-只是不能那样工作。在“主”线程中也是如此。