如何在不牺牲性能的情况下维护良好的代码组织?

时间:2011-01-13 18:40:11

标签: perl performance code-organization

我认为变量不应该在你打算使用它们之前初始化。它可以更容易地记住变量代表什么,如果它是由消耗它的代码,并且它减少了变量在初始化和正确使用之间被滥用的可能性。

当使用该变量在一个或两个循环内时,会出现问题。然后,初始化的成本会成倍增加,并可能开始影响性能。

在Perl中(或者通常,在适当的情况下),它们是否有任何简洁的技术,允许您将变量的初始化置于循环中,但是只能在第一次传递时初始化?

我想到了类似的东西:

my $variable = undef;
while ($outer_loop) {
    while ($inner_loop) {
       $variable = $variable || 'initial_value'
    }
}

注意:这意味着$variable不会在循环中重新分配。

现在也许是我,但这看起来有点不雅。

所以,这是我的问题:有没有更简洁的方法来做到这一点,或者我只是需要过度自我并在代码组织方面做出妥协,或者在上面采用那种“不优雅”的解决方案?

3 个答案:

答案 0 :(得分:6)

解决评论中的问题(变量在函数中计算):

  • 用于优化此类逻辑的标准技术称为 memoization (该函数)。在其他方法中,Perl具有Memoize模块,或者您可以自己完成。

      use Memoize;
      memoize('slow_function');
      while ($outer_loop) {
          while ($inner_loop) {
              my $variable = slow_function(arguments);
          }
      }
    
  • 此外,如果函数在整个循环中始终产生100%相同的值(按设计),只需通过在循环之前的语句中初始化变量来执行穷人的memoization。

    如果你有一个3页长的循环(例如,在循环之前进行初始化是一个与循环内部相比的可读性问题那么长),你有一个比初始化行的位置更大的编码问题,并且需要首先重新考虑你的代码。

    顺便说一句,如果你唯一关心的是在循环之前放置变量是因为它破坏了“这个变量只在这个循环中使用”的可读性上下文,你可以通过以下任一方式轻松解决它:

    • 记录良好的代码 - 相应地命名变量,或者在初始化行中添加注释,或两者都添加。

    • 或者,通过命名类似my $default_value_for_next_loop = long_func();的变量,并在循环内部实际创建一个从其初始化的本地循环变量:my $loop_var = $default_value_for_next_loop;

另外,就你自己的方法而言($variable = $variable || 'initial_value';); 我个人觉得这绝对优雅可读,但是!我很确定它实际上比直接$variable = $default_value_for_next_loop;执行更差,因为它有条件语句而不是直接赋值。但如果没有基准测试,我无法确定。

答案 1 :(得分:4)

  

当使用该变量在一个或两个循环内时,会出现问题。然后,初始化的成本会成倍增加,并可能开始影响性能。

是吗?你测量过吗?如果你的$variable在两个循环中都适用于代码,那么我会按如下方式编写循环:

my $variable = 'initial_value';
while ($outer_loop) {
    while ($inner_loop) {
       # ...
    }
}

这样,读者就知道$variable用于以下代码部分,以及它的初始值是什么。在您的代码段中,读者必须在循环深处的某处找到实际初始值。

此处不太可能存在性能问题,但如果这是一个关键因素,则应始终衡量性能。

答案 2 :(得分:3)

我认为你的指引有点太过分了。阻止滥用变量的最佳方法是延迟它的声明,直到它需要它为止。 (因此将其限制在最小可能的词法范围内。)延迟初始化并不能防止滥用;它只是为某人创造了一个机会,可以使用未定义的值,抢占您自己的初始化,或者将您的变量用于完全不相关的目的。

如果变量需要初始值/默认值,则应尽可能将其作为声明的一部分。这清楚地表明该变量具有起始值。

my $x = 1;
my $y = f($x);

延迟初始化意味着没有初始值。如果没有,或者如果你不能提前确定,那就没关系了,但是你后来偷偷溜过$var //= 'value'就牺牲了清晰度。

对于需要在循环迭代中保留其值的变量,您必须在循环外声明它们。有时我会在一个额外的块中包装循环,以防止这些变量泄漏到以下代码中:

{
    my $i = 5;
    for (1 .. 10) {
        say $i++;
    }
}