lua - lua:全局变量与表条目变量
问题描述
在lua中,当您在表中有一个函数时,在函数中声明全局变量与将变量声明为表中的条目(如果有)有什么区别?在下面的示例中,变量是 x。
IE
dog={x=33,
func=function(self)
self.x=self.x*self.x
end
}
cat={func=function()
x=33
x=x*x
end
}
在 dog 中,我可以使用 self 的属性通过 dog:func() 而不是 dog.func(dog) 调用函数。但除此之外,在两者之间进行选择时,是否有任何性能方面需要考虑的因素?这些示例在循环中调用时会有所不同,但除此之外呢?
解决方案
好吧,我听说关于优化的第一条规则是“不要这样做!” 和“不要这样做!”。
有一个官方文档公开了一些优化 Lua 代码的方法,我推荐它。最重要的规则是更喜欢局部变量而不是全局变量,因为全局变量比局部变量慢 30%。
我们可以对前面的代码做的第一件事是编译它并检查字节码指令以了解执行时发生的情况。我将第一个函数存储在“test-1.lua”中,第二个函数存储在“test-2.lua”中。
> cat test-1.lua
dog={x=33,
func=function(self)
self.x=self.x*self.x
end
}
function TEST ()
dog:func()
end
> luac54 -l -s test-1.lua
#
#(part of output omitted for clarity)
#
# Function: dog.func
#
function <test-1.lua:2,4> (6 instructions at 0000000000768740)
1 param, 3 slots, 0 upvalues, 1 local, 1 constant, 0 functions
1 [3] GETFIELD 1 0 0 ; "x"
2 [3] GETFIELD 2 0 0 ; "x"
3 [3] MUL 1 1 2
4 [3] MMBIN 1 2 8 ; __mul
5 [3] SETFIELD 0 0 1 ; "x"
6 [4] RETURN0
#
# Function: TEST (function to call dog.func)
#
function <test-1.lua:7,9> (4 instructions at 00000000000a8a90)
0 params, 2 slots, 1 upvalue, 0 locals, 2 constants, 0 functions
1 [8] GETTABUP 0 0 0 ; _ENV "dog"
2 [8] SELF 0 0 1k ; "func"
3 [8] CALL 0 2 1 ; 1 in 0 out
4 [9] RETURN0
所以,如果我们要执行TEST
10 次,我们至少需要执行 10*(4+6) 条字节码指令,也就是 100 条字节码指令。
> cat test-2.lua
cat={func=function()
x=x*x
end
}
x=33
function TEST ()
cat.func()
end
> luac54 -l -s test-2.lua
#
#(part of output omitted for clarity)
#
# Function: cat.func
#
function <test-2.lua:1,3> (6 instructions at 00000000001b87f0)
0 params, 2 slots, 1 upvalue, 0 locals, 1 constant, 0 functions
1 [2] GETTABUP 0 0 0 ; _ENV "x"
2 [2] GETTABUP 1 0 0 ; _ENV "x"
3 [2] MUL 0 0 1
4 [2] MMBIN 0 1 8 ; __mul
5 [2] SETTABUP 0 0 0 ; _ENV "x"
6 [3] RETURN0
#
# Function: TEST (function to call cat.func)
#
function <test-2.lua:8,10> (4 instructions at 00000000001b8a80)
0 params, 2 slots, 1 upvalue, 0 locals, 2 constants, 0 functions
1 [9] GETTABUP 0 0 0 ; _ENV "cat"
2 [9] GETFIELD 0 0 1 ; "func"
3 [9] CALL 0 1 1 ; 0 in 0 out
4 [10] RETURN0
所以,如果我们要执行TEST
10 次,我们至少需要执行 10*(4+6) 条字节码指令,也就是 100 条字节码指令......这和第一个版本完全一样!
显然,所有字节码指令的执行时间并不相同。C
一些指令将在运行时花费更多时间,而其他指令将花费更多时间。两个整数相加可能比分配新表和初始化一些字段要快得多。那时,我们可以尝试做一个肮脏和毫无意义的事情microbenchmark
来给我们一个想法。
可以将这段代码复制并粘贴到Lua
解释器中:
> cat dirty-and-pointess-benchmark.lua
dog={x=33,
func=function(self)
self.x=self.x*self.x
end
}
cat={func=function()
x=x*x
end
}
x=33
function StartMeasure ()
StartTime = os.clock()
end
function StopMeasure (TestName)
local Duration = os.clock() - StartTime
print(string.format("%s: %f sec", TestName, Duration))
end
function DoTest1 (Count)
for Index = 1, Count do
dog:func()
end
end
function DoTest2 (Count)
for Index = 1, Count do
cat.func()
end
end
COUNT = 5000000000
StartMeasure()
DoTest1(COUNT)
StopMeasure("VERSION_1")
StartMeasure()
DoTest2(COUNT)
StopMeasure("VERSION_2")
这段代码在我的电脑上给出了这个结果:
VERSION_1: 246.816000 sec
VERSION_2: 250.412000 sec
显然,对于大多数程序而言,差异可能可以忽略不计。我们应该始终尝试将更多时间花在编写正确的程序上,而花更少的时间来做微基准测试。
推荐阅读
- porting - 将 word2vec 移植到 RISC-V.. 潜在的代理内核问题?
- laravel-5 - 请求实体太大问题
- python - 美丽的汤蟒 - 把名字放在一起/查找 - 找到所有
- html - 无法启动使用引导程序关闭的折叠 div
- java - Java Weka - 如何标准化单个实例
- ios - 如何获取 EKEvent 的下一个发生日期?
- java - Java - 将用户输入数据传递给 if / else 语句
- javascript - 单击按钮时关闭模式?
- codeigniter - Codeigniter 3 - 查询生成器“加入”方法“!=”运算符未提供预期输出
- c - 为什么要重置全局静态变量?