通过引用子例程传递大哈希的性能降低

时间:2014-07-28 17:26:47

标签: arrays performance perl hash

此代码

        foreach my $ti (@forward){
           my $new_bs = %blast_values->{ $ti }->{"bitscore"};
           if($new_bs > $fbs){
              $fti = $ti;
              $fbs = $new_bs;
           }
        }
        my $fqstart  = %blast_values->{ $fti }->{"qstart"};
        my $fqend    = %blast_values->{ $fti }->{"qend"};
        my $fsstart  = %blast_values->{ $fti }->{"sstart"};
        my $fsend    = %blast_values->{ $fti }->{"send"};

最初是通过子程序调用完成的:

        my ($fti, $fqstart, $fqend, $fsstart, $fsend, $fbs) = best_one(\@forward,\%blast_values);

在子程序内部:

        my @forward = @{$_[0]};
        my %blast_values = %{$_[1]};

然而,子程序版本的运行速度比本文顶部显示的代码慢了约40倍。子程序版本是相同的代码,只是移入子程序然后返回指示的标量值。如果我让它运行完成,子程序将被调用大约30K次,这是我从未做过的,因为它需要大约1800秒。将调试输出行放在&#34; foreach&#34;之前。在子程序中,在运行期间输出线之间存在明显的延迟,大约为1秒,而对于perl主要部分中的版本,没有可测量的延迟(因此输出线之间<0.1秒左右) )。

数组通常非常小,有1或2个(99%的时间)条目,很少有12个。另一方面,哈希非常非常大。它有1.5M键,每个键有6个由子键访问的值。两者都是通过引用传递的,所以它们的内容大小确实不应该重要。

可能导致这种延迟的原因是什么?我不记得在Perl子程序调用上有这么多的调用开销,并且输入参数是通过引用传递的,所以它不必复制巨大的哈希。 (虽然执行速度表明它可能正在这样做。)

Centos 5上的Perl 5.8.8。

1 个答案:

答案 0 :(得分:6)

这很慢,因为当你这样做时

my @forward = @{$_[0]};
my %blast_values = %{$_[1]};

您正在取消引用您传入的引用并引用的结构复制到新变量中。如果%blast_values非常大,那就是很多工作。

相反,只需使用引用而不复制。 (这就是他们的目的。)

my $forward = shift;
my $blast_values = shift;

my $fqstart  = $blast_values->{ $fti }->{"qstart"};
# etc

另外,我假设你知道%blast_values->{ $fti }->{"qstart"}没有意义。它完全有效的事实是由于Perl中的一个错误。使用这样的构造已经发出警告(“使用哈希作为参考被弃用”)多年。您应该使用$blast_values{ $fti }->{"qstart"}