【问题标题】:Nitpicking: Tcl storing in a variable or not, for speed, in procedures吹毛求疵:Tcl 是否存储在变量中,为了速度,在程序中
【发布时间】:2017-11-21 12:20:25
【问题描述】:

这是一个普遍的问题。假设 TCL 8.6,假设我有一个相当短的程序。我有 2 种方法可以返回感兴趣的值:
1. 使用一些标准做法 if/else 代码,存储在变量中,并返回变量的值。例如:

proc me { gop goo } {
   if { [ lomsa $gop ] {
      set ret [ foo $goo $gop ]
   } else {
      set ret [ bar $gop $goo ]
   }
   return $ret
}

2。使用三元参数,基本上,程序没有添加私有变量(即只使用参数)。三元表达式的输出是返回值。例如:

proc me { gop goo } {
   expr { [ lomsa $gop ] ? [ foo $goo $gop ] : [ bar $gop $goo ] }
}

我团队的一些成员认为可读性在第 1 项中稍好一些。
我无法在我的 TCL 设置中访问伪代码引擎(它是来自供应商的 shell),但我认为代码的差异及其性能会是,但如果有的话,也只是轻微的。即,该过程需要将返回的值存储在某处。为它注册一个特定变量的成本是多少,而不是将其保留为返回值?
这个问题可以扩展,例如,对于 switch 语句。同样的规则适用。 switch 语句可以存储在变量中,然后在 switch 之后返回变量的值,或者 switch 语句将只返回值,而不将其存储在变量中。此外,在它的返回部分之前可能有大量代码。上面列出的过程就是他们所说的“便利过程”
您可以假设代码的性能非常重要。

【问题讨论】:

    标签: variables return tcl store ternary


    【解决方案1】:

    有疑问时,不要猜测; time它!

    对于您的示例代码,对于 lomsafoobar 的最微不足道的实现,性能差异在百分之几之内,我可以侥幸逃脱(并且理解有一些小的一些边缘情况下的技术差异)。对于任何更复杂的事情,您会陷入困境,因为您正在平衡局部变量访问的成本与对操作码的额外调用,如果可能的话,将值转换为数值,而更慢的是“它取决于”领域.

    switch 语句在处理它完全可以编译的情况时,使用 Tcl 评估堆栈作为临时存储。如果我再次编写字节码编译,我可能会使用一个临时局部变量(它们是无名的;你不能从你的代码中触摸它们)以便保留一些其他计算更简单。要知道哪个是最快的选择,请为您的实际代码计时;对一些不太复杂的代理代码进行计时很容易得出相反的结论。

    在未来,差异应该更不重要。我们正在研究一种编译为高效本机代码的方法。我们开发的编译策略几乎消除了您在上面看到的差异,甚至在我们开始研究实际代码生成之前。

    【讨论】:

      【解决方案2】:

      除了可读性之外,三元运算符可能会产生意想不到的结果。例如,如果选定的 proc 返回 0123,则您的 me proc 将返回 83。因此,除非您确定这种情况永远不会发生,否则使用 if 命令会更安全。

      【讨论】:

      • 哇!我需要提出一个新问题才能了解为什么会发生这种情况。
      【解决方案3】:

      编译为字节码,两个版本的命令没有太大区别:在这两种情况下,选择结构都被转换为分支指令。

      要大致了解您的代码在编译后并准备好运行的样子,请使用tcl::unsupported::disassemble proc <name-of-proc>。一些警告:该命令不受支持,这意味着它不能保证按照您期望的方式工作,或者在未来的版本中继续按照现在的方式工作。除非您非常熟悉字节码解释器的工作原理,否则查看反汇编列表也可能比您认为的更具误导性。

      要了解有关性能的更多信息,您应该查看time 命令和bench 包,它们对于衡量性能非常有用。

      文档: bench (package), time

      【讨论】:

      • 我知道要利用时间。我对引擎盖下的东西很感兴趣。更深入的了解...
      • @user1134991:你也熟悉tcl::unsupported::disassemble吗?
      【解决方案4】:

      中间立场呢?

      proc me { gop goo } {
         if { [lomsa $gop] } {
            foo $goo $gop
         } else {
            bar $gop $goo
         }
      }
      

      或者如果你喜欢明确的返回:

      proc me { gop goo } {
         if { [lomsa $gop] } {
            return [foo $goo $gop]
         } else {
            return [bar $gop $goo]
         }
      }
      

      【讨论】:

      • 最后一个中断,因为参数应该是不同的顺序。
      • 确实,我错过了。它们看起来太相似了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-27
      • 1970-01-01
      • 1970-01-01
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-04
      相关资源
      最近更新 更多