加速 TCL 评估

accelerate Tcl eval

我目前正在编写一个用于符号矩阵操作的基于 Tcl 的工具,但是代码越来越慢。我正在寻找加速我的 Tcl 代码(Tcl 版本 8.6)的方法。

我有一个怀疑。我的代码构建列表,其中命令名称作为第一个元素,命令参数作为以下元素(这来自模拟面向对象的方法)。我使用 eval 调用这些命令(这​​在递归处理中经常完成)。我在 https://wiki.tcl-lang.org/page/eval and https://wiki.tcl-lang.org/page/Tcl+Performance 读到 eval 可能很慢。

我有三个问题:

  1. 从具有命令名称和参数的列表中调用命令的最快方法是什么?

  2. 是否会加速代码以分隔命令名称 myCmd 和参数列表 myPar 并使用 [$myCmd {*}$myPar] 调用命令(建议在 )?

  3. 使用 if 1 而不是 eval 的技巧在 8.6 中仍然有希望吗?

非常感谢您的帮助!

最重要的是,不要假设:time它是肯定的。请注意,在对重复 运行 某事物 进行计时时,可能 会改变 运行 它所花费的时间(随着缓存预热)。仔细想想你想要什么实际上得到的速度。

eval 命令通常很慢,但并非在所有情况下都如此。如果你给它一个列表你已经构建(例如,用listlinsertlappend或...)那么它相当快它可以避免重新解析输入;它知道,但 only 在那种情况下,它可以直接跳到调度命令实现。另一种快速的情况是当你给它一个之前给 eval 的值时;字节码已经构建并缓存。这些注意事项也适用于 uplevel.

$myCmd {*}$myParameters也相当快;这被字节编码为“assemble Tcl 操作数堆栈上的单词并执行正确的命令分派”,这非常接近于任意用户命令(很少有直接字节码实现)。

我希望使用 if 1 的东西在某些情况下会非常快,而在其他情况下会非常慢;它会强制进行完整编译,因此如果可以很好地缓存内容,那将会很快,如果不能缓存,则会很慢。而且,如果您只是调用一个命令,它充其量也不会产生太大影响。它获胜的情况是被调用的东西本身是一个字节编码的命令,你可以在其中正确缓存东西。

如果你正在处理一个普通的命令(例如,一个过程,或者触及 OS 的 Tcl 命令之一),我会选择选项 2:$myCmd {*}$myParameters 或变体在上面。它与您将要获得的速度一样快。但我不会这样做:

set myParameters [linsert $myOriginalValues 0 "literal1" [cmdOutput2] $value3]
$myCmd {*}$myParameters

太荒谬了。这样更清晰、更快速:

$myCmd "literal1" [cmdOutput2] $value3 {*}$myOriginalValues

扩展语法 ({*}) 的部分要点是您不需要进行复杂的参数编组,这很好,因为复杂性很难一直正确。

关于 K and unsharing objects

的注释

避免在内存中复制数据。变化

set mylist [linsert $mylist 0 some new content]

set mylist [linsert $mylist[set mylist ""] 0 some new content]

这会取消引用变量的值,然后将变量设置为 空字符串。这减少了变量的引用计数。

另见