Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 使用嵌套for循环的Perl脚本性能低下_Performance_Perl_For Loop_Nested Loops_Bioinformatics - Fatal编程技术网

Performance 使用嵌套for循环的Perl脚本性能低下

Performance 使用嵌套for循环的Perl脚本性能低下,performance,perl,for-loop,nested-loops,bioinformatics,Performance,Perl,For Loop,Nested Loops,Bioinformatics,我有一个大的FASTA文件(一个基因序列,一个完整的染色体),其中每行包含50个字符(碱基a、g、t和c)。这个文件中大约有400万行 我想重新组织文件,以便将一行中的每个字符放置在新文件中自己的行中。也就是说,将原始文件中的每50个字符行转换为50个单字符行。这将导致整个序列重写为一列。最后,我希望序列是一个单列,这样我就可以放置一个相邻的列,包含每个碱基的基因组坐标位置 我就是这样做的,使用perl并为循环创建一组 unless(@ARGV) { # $0 name of the p

我有一个大的FASTA文件(一个基因序列,一个完整的染色体),其中每行包含50个字符(碱基a、g、t和c)。这个文件中大约有400万行

我想重新组织文件,以便将一行中的每个字符放置在新文件中自己的行中。也就是说,将原始文件中的每50个字符行转换为50个单字符行。这将导致整个序列重写为一列。最后,我希望序列是一个单列,这样我就可以放置一个相邻的列,包含每个碱基的基因组坐标位置

我就是这样做的,使用perl并为循环创建一组

unless(@ARGV) {
    # $0 name of the program being executed;
    print "\n usage: $0 filename\n\n"; 
    exit;
}

# use shift to pull off @ARGV value and return to $list;
my $fastafile = shift; 
open(FASTA, "<$fastafile");
my @count =(<FASTA>);
close FASTA;

# print scalar @count;

for ( my $i = 0; $i < scalar @count ; $i ++ ) {

#print "$count[$i]\n\n\n\n"; 
my @seq  = split( "", $count[ $i ] ); 
print " line = $i ";
for ( my $j = 0; $j < scalar @seq; $j++ ){
    #my $count =
    print "$seq[$j]  for count = $j \n"; 

    }

}
除非(@ARGV){
#$0正在执行的程序的名称;
打印“\n用法:$0文件名\n\n”;
出口
}
#使用shift提取@ARGV值并返回到$list;
我的$fastafile=shift;

open(FASTA,“问题在于您正在对文件进行slurp处理。在对大文件进行slurp处理时,进程将等待所有I/O完成后才开始处理。一个选项是逐行处理文件:

open my $fh, '<', $fastafile or die "Error opening file: $!";

while ( my $line = <$fh> ) {
    chomp $line;    # Remove the newline from the end of each line

    my @seq = split //, $line;

    # Loop from 0 to the last index of @seq
    for my $i ( 0 .. $#seq ) {
        print "$seq[$i] for count = $i\n";
    }
}

打开我的$fh,”看起来您的主要限制是打印出的数据比读取的数据多几个数量级

如果每行是50个字符+换行符,则“应该”写入100/51(大约两倍)的数据

但是打印长字符串“X代表计数=29\n”意味着每个输入字符要写15-16个字符

除此之外,您还将消耗大量内存,但现在4M lines x 50 chars并不是真正的“太多”。不过,这是您不需要在这里“花费”的超过2000万的日常管理开销

也许在这个地方,编写自己的循环不如使用Perl操作符中的内置函数,比如
qq
aka

我还将变量构造移到循环之外,以节省更多的构造和垃圾收集时间

 {                            # Inner scope for local $" and my vars            #"
     local $" = "\n";         # Separator character for stringifying lists      #"
     my ($line, @line);       # Avoid cons/gc during the loop
     while ($line = <$fh>)
     {
           chomp $line;       # Strip any newline
           @line = split ('', $line);
           print "@line\n";   # Stringification using $"
     }
 }
{#本地$“和我的变量的内部作用域#”
本地$“=”\n“#字符串化列表的分隔符#”
我的($line,@line)#在循环过程中避免cons/gc
而($line=)
{
chomp$line;#删除任何新行
@行=拆分(“”,$line);
打印“@line\n”#使用$进行字符串化
}
}

(很抱歉,Stack Exchange的语法突出显示不知道$”是一个变量名,因此语法突出显示有点奇怪。)

以下内容可能会有所帮助:

use strict;
use warnings;

@ARGV or die "\n usage: $0 filename\n\n";

my $line = 0;
while (<>) {
    next if /^>/;
    chomp;

    print 'Line = ', $line++, "\n";
    my $count = 0;
    print "$_ for count = ", $count++, "\n" for split '';
    print "\n";
}
使用类来处理这个问题,它允许为fasta格式设置
width
block
(特定格式由处理)。如果我没记错的话,它有一些技巧来处理非常大的序列,尽管我认为这些仅限于编写部分(可耻的自我宣传,我去年实现了其中一个).像这样的东西应该很管用:

use Bio::SeqIO;

## omit the -format option and it will try to guess the format
my $in  = Bio::SeqIO->new(-file => $fastafile, -format => 'Fasta');

while (my $seq = $in->next_seq()) {
  my $out = Bio::SeqIO->new(-file => ">outputfilename", -format => 'Fasta');
  $out->width(1); # 1 base pair per line
  $out->write_seq($seq);
}
请注意,这将允许在同一个文件中包含多个fasta序列(使用一个包含6个序列和几行的fasta文件进行实验,以对其有一种感觉)

此外,这实际上写入了一个真正的fasta文件,因此您将无法更改代码来编写2列文件。但是您提到的问题,即第二列带有基索引,对我来说没有太大意义。如果您知道第一个基的偏移量,那么第二列只是$column_number+$offset+1(解释fasta头)。但是BioPerl有办法做到这一点,请不要重新发明轮子。将序列作为对象加载,并使用其方法获得子序列

my $in  = Bio::SeqIO->new(-file => $fastafile);

while (my $seq = $in->next_seq()) {
  ## $subseq will be a string with the sequence from bp 500 to 1000
  my $subseq = $seq->subseq(500, 1000);
}

我不确定这会给您带来多大的性能提升,但如果您认为您可以改进,请将其分享给BioPerl项目。

您使用fasta>标题做什么?在
for
循环之前,标题将被忽略。您能解释一下为什么要这样做吗?在我看来,这似乎是一个专业的标题你试图以错误的方式解决的问题,有点像你的问题是如何开门,答案是使用钥匙,但你问的是如何从安全距离炸门。嗯,也许我误解了,但输出目标实际上是“每行一个字符”还是“每行一个包含该字符的长字符串加上一个计数器”“?@carandraug,我最后想要的是一个两列文件,其中第一列是基,第二列是它的基因组坐标或基位置。序列来自UCSC基因组浏览器。你能注释
(0..$#seq)吗
…这说明了什么?或者
#
是一个打字错误?关于slurping,处理大约在6秒后开始,因此slurping所花费的时间与将输出打印到屏幕上所花费的时间相比并不短,这需要很长的时间。到目前为止,我等待了30分钟。终端窗口暂停(死亡之针轮旋转)每分钟左右,随着我的计算机风扇旋转。计算机变得越来越热。我明白了。我已经对范围部分进行了注释。我不能确定我的代码在这种情况下是否会运行得更快,因为我无法访问该文件。你能试试吗?$#var是Perl ese,表示“数组中的元素数@var”@BRPocock
$#var
是获取
@var
中最后一项的索引的语法。要获取数组中的项数,可以使用
标量(@var)
(如果标量已经在标量上下文中,可以省略
标量)。您能描述一下语法的含义吗?
打印“$\uFor count=”.$count++,“\n”对于split//;
它看起来非常精简。split//
表示什么意思/做什么?@ES55-不需要数组来执行您想要的处理。有问题的行首先
将序列拆分成它的字符,使用
for
循环对每个字符进行迭代--w
my $in  = Bio::SeqIO->new(-file => $fastafile);

while (my $seq = $in->next_seq()) {
  ## $subseq will be a string with the sequence from bp 500 to 1000
  my $subseq = $seq->subseq(500, 1000);
}