【问题标题】:How do I maintain good code organisation without sacrificing performance?如何在不牺牲性能的情况下保持良好的代码组织?
【发布时间】:2011-01-13 18:40:10
【问题描述】:

我赞同变量不应该在你将要使用它们之前被初始化的想法。如果变量是由将使用它的代码来表示的,那么它会更容易记住变量的含义,并且减少了变量在初始化和正确使用之间被误用的机会。

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

在 Perl 中(或一般情况下,适当时),它们是否有任何巧妙的小技巧可以让您将变量的初始化放在循环中,但只在第一次通过时才被初始化?

我想过这样的事情:

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

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

现在也许是我,但这似乎有点不雅。

所以,我的问题是:有没有更简洁的方法来做到这一点,还是我只需要克服自己并在代码组织上妥协,或者接受上面那个“不优雅”的解决方案?

【问题讨论】:

    标签: perl performance code-organization


    【解决方案1】:

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

    • 优化这种你想要的逻辑的标准技术称为memoization(该函数的)。在其他方法中,Perl 有Memoize 模块,或者你可以自己做。

        use Memoize;
        memoize('slow_function');
        while ($outer_loop) {
            while ($inner_loop) {
                my $variable = slow_function(arguments);
            }
        }
      
    • 另外,如果函数在整个循环中总是产生 100% 相同的值(按设计),只需在循环之前的语句中初始化变量,就可以简单地做一个穷人记忆。

      如果您有一个 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; 执行更差,因为它有一个条件语句而不是直接赋值。但如果没有基准测试,我无法确定。

    【讨论】:

    • 谢谢。我将仔细考虑这些选项,并找出哪个更适合我的特定模块……值得深思。
    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 确实……这不是一个简单的任务;该值是通过函数调用生成的。我同意,一般而言,衡量价值产生的成本并查看它是否重要可能会更好,但我仍然有兴趣看看是否有任何其他技术可以/通常/应用
    • 你希望多久处理一次代码 sn-p 进入循环足够远来调用你的初始化函数?在循环顶部初始化变量的代码仍然在做同样的工作,只是顺序不同。而且,您不必每次都通过内部循环检查变量是否已初始化。
    【解决方案3】:

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

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

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

    延迟初始化意味着没有初始值。如果没有,或者您无法提前确定,那也没关系,但您稍后会偷偷输入$var //= 'value',从而牺牲清晰度。

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

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

    【讨论】:

      猜你喜欢
      • 2012-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多