【问题标题】:Is instantiating a hash in a function inefficient in perl?在 perl 中实例化函数中的哈希效率低吗?
【发布时间】:2019-11-28 17:17:30
【问题描述】:

做以下,效率,坏习惯……有什么区别吗?

(在更大散列的上下文中并通过许多函数发送它们)

sub function {
  my ($self, $hash_ref) = @_;
  my %hash = %{$hash_ref};
  print $hash{$key};
  return;
}

相比:

sub function {
  my ($self, $hash_ref) = @_;
  print $hash_ref->{$key};
  return;
}

【问题讨论】:

  • 第一个无故复制散列。

标签: perl hash reference subroutine


【解决方案1】:

假设 %$hash_ref 包含 N 个元素。

除了第二个 sn-p 所做的之外,第一个 sn-p 还执行以下操作:

  • 创建 N 个标量。 (每个都可能涉及多个内存分配。)
  • 将 N*2 标量添加到堆栈中。 (便宜。)
  • 创建一个散列。 (更多内存分配...)
  • 将 N 个元素添加到哈希中。 (更多内存分配...)

除了第一个 sn-p 所做的之外,第二个 sn-p 还执行以下操作:

  • [什么都没有。它是第一个 sn-p 的完整子集]

因此,第一个 sn-p 的效率远低于第二个。由于有额外的代码,它也更加复杂。完全没有好处和大量的成本决定了人们应该避免使用第一个 sn-p 中使用的模式。

【讨论】:

  • 第一个 sn-p 中的模式的一个小好处:不能意外激活 %$hash_ref 的元素。但这在实践中从未发生过,因此这是一个毫无价值的好处。
  • 我不会说“永远不会发生”。在处理多级结构时经常发生这种情况。但更重要的是,当我明确不想修改原始哈希时,我只会使用第一种方法。
  • @Grinnz,很好,我从未见过这种情况发生。我什至不确定我是否听说过这件事。这主要是因为f($h{$k}) 专门防止发生自动激活,即使$h{$k} 被评估为左值。只有for ($h{$k}) { } 会这样做,谁会这样做?
  • @Grinnz,也许您正在考虑引用的自动激活? no autovivification; 是一种更好的保护措施。
【解决方案2】:

第一个 sn-p 很傻。但模拟命名参数是convenient practice

sub function {
   my ($self, %params ) = @_;
   ...
} 

所以,通过引用传递数组/哈希,创建新的(特别是大的)哈希会慢得多。但是“命名参数”hack 没有什么不好的。

您现在是否存在键/值切片(仅限 v5.20+)?您可以通过这种方式轻松复制部分哈希: 我的 %foo = ( 一 => 1, 二 => 2, 三 => 3, 四 => 4); 我的 %bar = %foo{'one', 'four'};

更多信息在perldoc perldata

【讨论】:

    【解决方案3】:

    sub 的第一个版本创建了数据结构的本地副本,引用被传递给它。当然,因此它的效率要低得多。

    这样做有一个合理的原因:确保调用者中的数据没有改变。那个本地的%hash可以根据需要或者方便在sub中修改,调用代码中的数据不受影响。这样,调用者中的数据也可以防止意外更改。

    完成数据的本地副本的另一个原因,特别是对于更深层次的数据结构,是为了避免长链的解引用,从而简化代码;因此可以复制深层层次结构的一部分以便更简单地访问。那么这仅仅是为了(假定的)编程方便。

    因此,在所示示例中,绝对没有理由制作本地副本。但是,大概问题是关于完成更多工作的潜艇,然后最好取决于细节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-01
      • 2012-08-22
      • 2011-06-14
      • 2016-05-10
      • 2020-07-19
      • 1970-01-01
      • 2011-10-04
      相关资源
      最近更新 更多