Performance Perl脚本正在工作,但速度太慢

Performance Perl脚本正在工作,但速度太慢,performance,perl,loops,Performance,Perl,Loops,我的脚本用于阅读以下形式的脚本: fixedStep chrom=chr1 start=3 step=1 0.006 0.010 fixedStep chrom=chr1 start=9 step=1 0.002 0.004 0.005 fixedStep chrom=chr1 start=14 step=1 0.010 0.020 0.028 0.666 0.777 fixedStep chrom=chr1 start=22 step=1 0.005 0.009 0.012 0.555 该脚

我的脚本用于阅读以下形式的脚本:

fixedStep chrom=chr1 start=3 step=1
0.006
0.010
fixedStep chrom=chr1 start=9 step=1
0.002
0.004
0.005
fixedStep chrom=chr1 start=14 step=1
0.010
0.020
0.028
0.666
0.777
fixedStep chrom=chr1 start=22 step=1
0.005
0.009
0.012
0.555
该脚本适用于此类简短的“练习文件”。其输出如下所示:

.....
.....
.....
0.006
0.010
.....
.....
.....
.....
0.002
0.004
0.005
.....
.....
0.010
0.020
0.028
0.666
0.777
.....
.....
.....
0.005
0.009
0.012
0.555
.....
.....
.....
.....
.....
因此,脚本所做的是在一列中列出从原始文件派生的两个重要内容。第一种重要的事情是所有的四位十进制数字。第二种重要的事情是
..
实例的可变数量。这些数字代表“缺失”的四位数字。在十进制数的任何连续延伸之前和之后出现的
..
数是根据以
fixedStep…
开头的行中包含的信息计算出来的

脚本的最终目的是将此处显示的实践文件的大版本转换为输出的大版本。但正如我所说,我的解决方案很慢。有改进的想法吗?我确实已经编写了另一个脚本来读取输出,并且该脚本期望以我刚才描述的特定格式输出

以下是脚本:

#!/usr/bin/perl

use strict; use warnings;

unless(@ARGV) {
    exit;
}

my $chrpc = shift;
open( PHAST, "<$chrpc" );
然后循环通过
@wholething
,将包含十进制数的文件的下一行以及包含
fixestep
的下一行推入
@chunked
,一个逗号,“end”,然后再次插入同一行,后跟一个逗号

for ( my $i = 1; $i < scalar @wholething ; $i++ ) {
       if ( $wholething[ $i ]=~m/fixedStep/ ){
       chomp $wholething[ $i ];
       push ( @chunked, $wholething[ $i ],",", "end\n", $wholething[ $i ], ","  ); 
  }    

  else {
      chomp $wholething[ $i ];
      push ( @chunked, $wholething[ $i ], "," );
  }
}
现在,随着文件重新组织,我开始创建新文件。我创建了一个容器
@pc_数组
,并将
$last
定义为某个值。回想一下上面的分块形式,除了最后一个分块之外,每一次十进制数都被相邻的
fixedStep
行括起来。
$last
给出的值用于帮助将最后一个块的末尾括起来。在这里,这个数字是巨大的。如果重要的话,这个值就是染色体序列的最终位置。输出的所有行都对应于染色体中的基本位置(因此文件很大)。对于练习文件,将
$last
设置为更小的数字

my @pc_array = ();
my $count = 1;
my $last = 61342429;  ## enter here value of final position for given chr.
一个
for loop
循环遍历每个块,并计算出在块之间添加多少
..
。第一次通过循环,我计算了在第一个十进制数之前要添加到数组中的
。在循环的最后一次中,我使用
$last
来帮助计算最后要添加多少
。对于其余部分,我将十进制数推入数组,然后是适当的
。我还在输出中生成一些健全性检查,以确保工作正常进行。我将在最后删除这些内容,以便生成输出的最终形式

for ( my $i = 0; $i < scalar @chunked_array  ; $i++ ) { ## $i = chunk number

      my @lines = split ( "," , $chunked_array[ $i ]);

      my $distance = scalar @lines - 2 ; ## gives number of pc score lines 
      ## notice extra comma in @entries. 


      my ( $position_1, $position_2 ) = ($chunked_array[ $i ] =~ /start\=(\d+)/g); 
      my $post_fill = $position_2 - ( $position_1 + $distance ) ;

      if ( $i == 0 ){ ## when first chunk

           push ( @pc_array, 0, 0, ".....\n" );

           for ( my $j = 0; $j < $position_1 - 1 ; $j++ ){

                 ## fill in 'pre-missing' scores with .'s

             push ( @pc_array, $i, $count, ".....\n" ); 
             $count++;
       } 

        ## fill in pc scores
        for( my $j = 0; $j < $distance; $j++ ){

             push( @pc_array, $i, $count, "$lines[ 1 + $j ]\n" ); 

             $count++;
         }

         ## fill in post-missing pc scores with .'s
         for ( my $j = 0; $j < $post_fill  ; $j++ ){
               push ( @pc_array, $i, $count, ".....\n" ); 
               $count++;
         } 

  } 


  elsif ( $chunked_array[ $i ] eq $chunked_array[ -1 ] ) {
          ## when last chunk

          ## fill in pc scores
          for( my $j = 0; $j < $distance; $j++ ){

               push( @pc_array, $i, $count, "$lines[ 1 + $j ]\n" ); 

               $count++;
          }

          my $final_post_fill = $last - ( $position_1 + $distance ); 

          ## fill is post-missing pc scores with .'s
          for ( my $j = 0; $j < $final_post_fill + 1  ; $j++ ){
               push ( @pc_array, $i, $count, ".....\n" ); 
               $count++;
         }



  }



  else { ## when first or else not the last chunk

        ## fill is pc scores
        for ( my $j = 0; $j < $distance; $j++ ){

             push( @pc_array, $i, $count, "$lines[ 1 + $j ]\n" ); 

             $count++;
         }

         ## fill is post-missing pc scores with .'s
         for ( my $j = 0; $j < $post_fill  ; $j++ ){
               push ( @pc_array, $i, $count, ".....\n" ); 
               $count++;
         } 

   }

}
我执行以下操作来删除空间,但主要是删除输出中的健全性检查,以获得所需输出的最终形式

my @pc_col =();

for ( my $i = 2; $i < @pc_array; $i=$i+3 ) {
      chomp $pc_array[ $i ];
      print "$pc_array[ $i ]\n";
      push ( @pc_col, $pc_array[ $i ]."\n");
}

print @pc_col;
open( OUT, ">chr19_pc_col.txt");
print OUT @pc_col;
my@pc_col=();
对于(我的$i=2;$i<@pc_阵列;$i=$i+3){
chomp$pc_数组[$i];
打印“$pc_数组[$i]\n”;
推送(@pc_col,$pc_数组[$i]。“\n”);
}
打印@pc_col;
打开(OUT,“>chr19_pc_col.txt”);
打印出@pc_col;

正如我所说,脚本可以工作,但我可以使用一些指针来优化它。

Slurping确实会导致大文件的性能问题

我不会为你做整件事,但看起来类似的模式可能会帮助你开始:

#buffer, holds a few lines of the input file
my @chunk_lines = ();

#read line-by-line until end of file
while (!eof $fh) {
    my $line = readline $fh;
    if ($line =~ /^fixedStep/) {      #if this line is the start of a new chunk...
        process_chunk(@chunk_lines);  #process data
        @chunk_lines = ();            #clear buffer
    }

    #either way, push this line onto the buffer
    push @chunk_lines, $line;
}

#process any remaining buffer
process_chunk(@chunk_lines);
如果您可以单独处理每个块,那就好了。您将一组值推送到一个数组中,然后将其拆分以进行处理的任何操作?这是一个你可以优化的地方

如果将空的
@chunk\u行
传递给
进程块
是错误的,您可以简单地避免:

process_chunk(@chunk_lines) if @chunk_lines;

你把自己弄得一团糟

据我所知,这个程序似乎能满足你的需要。我假设
step
属性总是一个,或者至少可以忽略,
chrom
字段也同样不相关

use strict;
use warnings;

open my $out, '>', 'chr19_pc_col.txt' or die $!;

my $last = 30;

my $line = 0;
while (<>) {
  if (/^fixedStep.*start=(\d+)/) {
    my $start = $1;
    while ($line < $start) {
      print $out ".....\n";
      ++$line;
    }
  }
  else {
    print $out $_;
    ++$line;
  }
}

print $out ".....\n" for $line .. $last;

close $out or die $!;

你的代码很难像那样分开阅读。通常最好在代码中加入尽可能少的注释。请描述一下,
fixedStep
行如何在输出中转换为虚线?我没有看到你提到的“两个
start=
实例后面跟一个数字”。对不起,这是一个打字错误。编辑掉了。好的,但请解释如何确定要添加的虚线数量。在
fixedStep
行中,有一个术语
start=
一些数字。该数字指的是后续十进制数字的位置号。因此,我需要在第一个十进制数之前添加3行。在数组中第一次运行十进制数之后,我需要添加4行
,因为下一个
start=
值是9。这是一个“零索引”类型的文件,其中第一行是0。很接近。它只是缺少最后一组
..
不确定您所指的
色度
字段是什么,或者
步骤
。有一个
$count
,我将它设置为1,然后用它来帮助计算初始输出中的行数,就像一个健全性检查一样。最后,我将其删除以生成最终输出。我试试你的主意。哦……是的,我现在明白你的意思了。是的,步骤属性总是1(我希望如此)。根据色度字段,这是指在输出的最后要做什么吗?无法知道要在最后添加多少行,因为
fixedStep
记录只说明下一个数字应该出现的位置。@ES55:
fixedStep
记录有
chrom
,一个
开始
和一个
步骤
属性。是的,没错。在我的脚本中,有一行我添加了最后一个位置的值(我称之为
$last
)。我可以修改你的答案来做到这一点。但是什么是
chrom
字段?我不明白那部分。
my @pc_col =();

for ( my $i = 2; $i < @pc_array; $i=$i+3 ) {
      chomp $pc_array[ $i ];
      print "$pc_array[ $i ]\n";
      push ( @pc_col, $pc_array[ $i ]."\n");
}

print @pc_col;
open( OUT, ">chr19_pc_col.txt");
print OUT @pc_col;
#buffer, holds a few lines of the input file
my @chunk_lines = ();

#read line-by-line until end of file
while (!eof $fh) {
    my $line = readline $fh;
    if ($line =~ /^fixedStep/) {      #if this line is the start of a new chunk...
        process_chunk(@chunk_lines);  #process data
        @chunk_lines = ();            #clear buffer
    }

    #either way, push this line onto the buffer
    push @chunk_lines, $line;
}

#process any remaining buffer
process_chunk(@chunk_lines);
process_chunk(@chunk_lines) if @chunk_lines;
use strict;
use warnings;

open my $out, '>', 'chr19_pc_col.txt' or die $!;

my $last = 30;

my $line = 0;
while (<>) {
  if (/^fixedStep.*start=(\d+)/) {
    my $start = $1;
    while ($line < $start) {
      print $out ".....\n";
      ++$line;
    }
  }
  else {
    print $out $_;
    ++$line;
  }
}

print $out ".....\n" for $line .. $last;

close $out or die $!;
.....
.....
.....
0.006
0.010
.....
.....
.....
.....
0.002
0.004
0.005
.....
.....
0.010
0.020
0.028
0.666
0.777
.....
.....
.....
0.005
0.009
0.012
0.555
.....
.....
.....
.....
.....