在TCL中,粗略地说,有可以通过global varname
访问的全局变量,或者可以通过namespace varname
命令访问的命名空间变量。
我非常简单地检查2的访问时间对于版本tcl 8.5,variable
与global
显示了微小且一致的运行时访问优势。
我们可以期待8.6及以上的情况,至少现在是这样吗?
答案 0 :(得分:4)
tl; dr: 非常两者之间的速度差别不大,还不够你应该关心。以语义正确的方式做事并留在那里。正确用于您的用例将在时间方面击败任何修补百分比。
让我们比较全局命名空间中执行相同操作的以下两个过程。请注意,我们比较的选项之间的差异权重将相对于实际代码人为地提高;这些是微观基准,应该被怀疑地对待。
# Using the default `epsilon` of 0.001
assert_in_epsilon(1_000, actual[0])
assert_in_epsilon(1_000_000, actual[1])
好的,时间信息(您的绝对时间 会因硬件而异):
assert_in_delta(1_000, actual[0], 1)
assert_in_delta(1_000_000, actual[1], 1000)
是的,proc a {} {
global x y
expr {$x + $y}
}
proc b {} {
variable x
variable y
expr {$x + $y}
}
略慢于% set x 123
123
% set y 456
456
% a
579
% b
579
% time { a } 10000
0.5720533 microseconds per iteration
% time { b } 10000
0.5756787999999999 microseconds per iteration
。让我们看看字节码,看看为什么:
b
您的Tcl版本中的确切字节码序列可能有所不同;这完全是实施的一部分,而不是官方界面。但是,我们可以看到,对于a
,操作码序列涉及命名实现中的一个% tcl::unsupported::disassemble proc a
ByteCode 0x0x10280fe10, refCt 1, epoch 15, interp 0x0x100829a10 (epoch 15)
Source "\n global x y\n expr {$x + $y"...
Cmds 2, src 35, inst 35, litObjs 4, aux 0, stkDepth 2, code/src 0.00
Proc 0x0x102822c10, refCt 1, args 0, compiled locals 2
slot 0, scalar, "x"
slot 1, scalar, "y"
Commands 2:
1: pc 0-19, src 5-14 2: pc 20-33, src 20-33
Command 1: "global x y"...
(0) push1 0 # "::"
(2) push1 1 # "x"
(4) nsupvar %v0 # var "x"
(9) push1 2 # "y"
(11) nsupvar %v1 # var "y"
(16) pop
(17) nop
(18) nop
(19) nop
Command 2: "expr {$x + $y}"...
(20) startCommand +14 1 # next cmd at pc 34, 1 cmds start here
(29) loadScalar1 %v0 # var "x"
(31) loadScalar1 %v1 # var "y"
(33) add
(34) done
% tcl::unsupported::disassemble proc b
ByteCode 0x0x10280fa10, refCt 1, epoch 15, interp 0x0x100829a10 (epoch 15)
Source "\n variable x\n variable y\n expr {$x + $"...
Cmds 3, src 50, inst 44, litObjs 3, aux 0, stkDepth 2, code/src 0.00
Proc 0x0x102822a90, refCt 1, args 0, compiled locals 2
slot 0, scalar, "x"
slot 1, scalar, "y"
Commands 3:
1: pc 0-9, src 5-14 2: pc 10-28, src 20-29
3: pc 29-42, src 35-48
Command 1: "variable x"...
(0) push1 0 # "x"
(2) variable %v0 # var "x"
(7) nop
(8) nop
(9) nop
Command 2: "variable y"...
(10) startCommand +18 1 # next cmd at pc 28, 1 cmds start here
(19) push1 2 # "y"
(21) variable %v1 # var "y"
(26) push1 1 # ""
(28) pop
Command 3: "expr {$x + $y}"...
(29) startCommand +14 1 # next cmd at pc 43, 1 cmds start here
(38) loadScalar1 %v0 # var "x"
(40) loadScalar1 %v1 # var "y"
(42) add
(43) done
命名空间句柄和两个global
,以及两个push1
调用时,不会推送命名空间,但nsupvar
操作码使用两次,两者之间有一个额外的variable
。 variable
是一个混乱的基础设施,其副作用是抑制一些小的优化,因此可能是原因。
如果两者之间存在这么小的差异,那么确定性能差异的地方就需要像cachegrind这样的工具......
BTW,尝试将性能与此进行比较:
startCommand
与上面的startCommand
程序有完全相同的字节码序列...