挑剔:Tcl 是否存储在变量中,为了速度,在过程中

Nitpicking: Tcl storing in a variable or not, for speed, in procedures

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

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

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

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

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

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

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

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

文档: bench (package), time

中间地带呢?

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

或者如果你喜欢明确的 return:

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

如有疑问,请勿猜测; time啦!

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

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

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

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