【发布时间】:2016-07-22 16:15:24
【问题描述】:
我多次提到最好将脚本放入 proc 以提高运行时性能,例如this answer 有以下内容:
这是建议将所有代码放入过程中的原因之一(它们会以这种方式进行字节编译)
有些东西没有点击我。
正如答案中所述,第一次运行脚本时,会检查命令是否可以编译字节码,如果可以,则编译。这完全有道理。但我看不出“proc”如何发挥重要作用。例如。比较以下 2 个脚本:
set v [concat [lindex $::argv 1] [lindex $::argv 2]]
myCmd $v
和
proc p1 {v1 v2} {
set v [concat $v1 $v2]
return [myCmd $v]
}
p1 [lindex $::argv 1] [lindex $::argv 2]
我对这 2 个脚本的高级解释如下:
- 在第一次运行任一脚本时,都会编译“set”、“concat”、“lindex”和“return”命令
- 第二个脚本也编译了“proc”。
- “myCmd”未在任一脚本中编译
- 随后运行任一脚本都会运行除“myCmd”之外的副代码。
那么“proc”有什么好处呢?
我确实在脚本上运行了 dissamble:
第一个脚本:
ByteCode 0x0x83fc70, refCt 1, epoch 3, interp 0x0x81d680 (epoch 3)
Source "set v [concat [lindex $::argv 1] [lindex $::argv 2]]\nmy"
Cmds 5, src 61, inst 50, litObjs 4, aux 0, stkDepth 4, code/src 0.00
Commands 5:
1: pc 0-41, src 0-51 2: pc 2-39, src 7-50
3: pc 4-20, src 15-30 4: pc 21-37, src 34-49
5: pc 42-48, src 53-60
Command 1: "set v [concat [lindex $::argv 1] [lindex $::argv 2]]"
(0) push1 0 # "v"
Command 2: "concat [lindex $::argv 1] [lindex $::argv 2]"
(2) push1 1 # "concat"
Command 3: "lindex $::argv 1"
(4) startCommand +17 1 # next cmd at pc 21
(13) push1 2 # "::argv"
(15) loadScalarStk
(16) listIndexImm 1
Command 4: "lindex $::argv 2"
(21) startCommand +17 1 # next cmd at pc 38
(30) push1 2 # "::argv"
(32) loadScalarStk
(33) listIndexImm 2
(38) invokeStk1 3
(40) storeScalarStk
(41) pop
Command 5: "myCmd $v"
(42) push1 3 # "myCmd"
(44) push1 0 # "v"
(46) loadScalarStk
(47) invokeStk1 2
(49) done
第二个脚本:
ByteCode 0x0xc06c80, refCt 1, epoch 3, interp 0x0xbe4680 (epoch 3)
Source "proc p1 {v1 v2} {\n set v [concat $v1 $v2]\n return"
Cmds 4, src 109, inst 50, litObjs 5, aux 0, stkDepth 4, code/src 0.00
Commands 4:
1: pc 0-10, src 0-67 2: pc 11-48, src 69-108
3: pc 13-29, src 73-88 4: pc 30-46, src 92-107
Command 1: "proc p1 {v1 v2} {\n set v [concat $v1 $v2]\n return"
(0) push1 0 # "proc"
(2) push1 1 # "p1"
(4) push1 2 # "v1 v2"
(6) push1 3 # "\n set v [concat $v1 $v2]\n return ["
(8) invokeStk1 4
(10) pop
Command 2: "p1 [lindex $::argv 1] [lindex $::argv 2]"
(11) push1 1 # "p1"
Command 3: "lindex $::argv 1"
(13) startCommand +17 1 # next cmd at pc 30
(22) push1 4 # "::argv"
(24) loadScalarStk
(25) listIndexImm 1
Command 4: "lindex $::argv 2"
(30) startCommand +17 1 # next cmd at pc 47
(39) push1 4 # "::argv"
(41) loadScalarStk
(42) listIndexImm 2
(47) invokeStk1 3
(49) done
所以脚本 2 确实少了 1 个 TCL 命令,但两个脚本都有 49 字节码命令。
最后运行测试,我注释掉“myCmd”,因为我实际上没有这样的扩展。结果如下:
% time {source 1.tcl} 10000
242.8156 microseconds per iteration
% time {source 2.tcl} 10000
257.9389 microseconds per iteration
所以 proc 版本更慢。
我错过了什么?或者说,proc和performance的确切理解是什么?
【问题讨论】:
-
concat通常是一个相当昂贵的操作,FWIW。
标签: tcl