加速 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
可能很慢。
我有三个问题:
从具有命令名称和参数的列表中调用命令的最快方法是什么?
是否会加速代码以分隔命令名称 myCmd
和参数列表 myPar
并使用 [$myCmd {*}$myPar]
调用命令(建议在 )?
使用 if 1
而不是 eval
的技巧在 8.6 中仍然有希望吗?
非常感谢您的帮助!
最重要的是,不要假设:time
它是肯定的。请注意,在对重复 运行 某事物 进行计时时,可能 会改变 运行 它所花费的时间(随着缓存预热)。仔细想想你想要什么实际上得到的速度。
eval
命令通常很慢,但并非在所有情况下都如此。如果你给它一个列表你已经构建(例如,用list
或linsert
或lappend
或...)那么它相当快它可以避免重新解析输入;它知道,但 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
扩展语法 ({*}
) 的部分要点是您不需要进行复杂的参数编组,这很好,因为复杂性很难一直正确。
的注释
避免在内存中复制数据。变化
set mylist [linsert $mylist 0 some new content]
至
set mylist [linsert $mylist[set mylist ""] 0 some new content]
这会取消引用变量的值,然后将变量设置为
空字符串。这减少了变量的引用计数。
另见
我目前正在编写一个用于符号矩阵操作的基于 Tcl 的工具,但是代码越来越慢。我正在寻找加速我的 Tcl 代码(Tcl 版本 8.6)的方法。
我有一个怀疑。我的代码构建列表,其中命令名称作为第一个元素,命令参数作为以下元素(这来自模拟面向对象的方法)。我使用 eval
调用这些命令(这在递归处理中经常完成)。我在 https://wiki.tcl-lang.org/page/eval and https://wiki.tcl-lang.org/page/Tcl+Performance 读到 eval
可能很慢。
我有三个问题:
从具有命令名称和参数的列表中调用命令的最快方法是什么?
是否会加速代码以分隔命令名称
myCmd
和参数列表myPar
并使用[$myCmd {*}$myPar]
调用命令(建议在 )?使用
if 1
而不是eval
的技巧在 8.6 中仍然有希望吗?
非常感谢您的帮助!
最重要的是,不要假设:time
它是肯定的。请注意,在对重复 运行 某事物 进行计时时,可能 会改变 运行 它所花费的时间(随着缓存预热)。仔细想想你想要什么实际上得到的速度。
eval
命令通常很慢,但并非在所有情况下都如此。如果你给它一个列表你已经构建(例如,用list
或linsert
或lappend
或...)那么它相当快它可以避免重新解析输入;它知道,但 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
扩展语法 ({*}
) 的部分要点是您不需要进行复杂的参数编组,这很好,因为复杂性很难一直正确。
避免在内存中复制数据。变化
set mylist [linsert $mylist 0 some new content]
至
set mylist [linsert $mylist[set mylist ""] 0 some new content]
这会取消引用变量的值,然后将变量设置为 空字符串。这减少了变量的引用计数。
另见