【问题标题】:Slow performance on passing large hash by reference to subroutine通过引用子例程传递大哈希时性能缓慢
【发布时间】:2014-07-28 17:26:47
【问题描述】:

这段代码

        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 秒。将调试输出行放在子例程中的“foreach”之前,并且在运行期间输出行之间存在明显的延迟,大约为 1 秒,而对于 perl 主要部分中的版本,没有可测量的延迟(所以

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

造成这种延迟的原因是什么?我不记得 Perl 子例程调用有这么多的调用开销,并且输入参数是通过引用传递的,所以它不必复制巨大的散列。 (尽管执行速度表明它可能正在这样做。)

Centos 5 上的 Perl 5.8.8。

【问题讨论】:

  • 为什么要复制 (my @forward = @{$_[0]}; my %blast_values = %{$_[1]};)?使用my ($forward, $blast_values) = @_;
  • my ($forward, $blast_values) = @_; 及以后使用 $forward->[x] 和 $blast_values->{y}。

标签: arrays performance perl hash


【解决方案1】:

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

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"}

【讨论】:

  • 应该是这样吗?我的@forward = $_[0];我的 %blast_values = $_[1];
  • 在通过引用传递哈希的示例中经常遇到这种语法:my $params = shift;我的 %paramhash = %$params;这是否也取消引用(复制)哈希?没关系,在我看到的线程的更下方,我现在看到它说该方法确实复制了。
  • my ($forward, $blast_values) = @_; 比一次转移一个值要快,尤其是在 5.20 及更高版本上。
猜你喜欢
  • 1970-01-01
  • 2011-10-22
  • 2016-12-04
  • 1970-01-01
  • 2011-01-17
  • 2014-12-18
  • 1970-01-01
  • 2011-06-21
  • 2017-07-18
相关资源
最近更新 更多