lua的本地VS全球

时间:2014-10-02 05:34:34

标签: performance parameters lua global local

每个消息来源都同意这一点:

  

the access to local variables is faster than to global ones

在实际使用中,主要区别在于如何处理变量,因为它仅限于范围,不能从代码的任何一点访问。

从理论上讲,局部变量可以避免非法更改,因为它无法从错误的点访问,甚至可以更好地查找var。

现在我想知道这个概念的细节; 技术上如何工作,代码的某些部分可以访问,其他部分不能访问? 表演有多么适合?

但主要问题是: 让我们提一下我有一个var bazinga =“太酷了。”并希望从某个地方改变它。 由于字符串是公开的,我可以很容易地做到这一点。 但是现在,如果它被声明为本地并且我超出了范围,那么,如果我通过X函数切换变量,那么获得访问权限需要做出哪些性能:

func_3(bazinga)
    func_N(bazinga)
end
func_2(bazinga)
   func_3(bazinga)
end

func_1()
  local bazinga = "So cool."
  func_2(bazinga) 
end

太过分了,局部变量保持了更高的性能以及为什么?

我问你,由于维护代码被移交给许多函数的代码变得一团糟,我想知道,如果真的值得的话。

3 个答案:

答案 0 :(得分:4)

  

从理论上讲,局部变量可以避免非法更改,因为它无法从错误的点访问,甚至可以更好地查找var更高效。

在实际意义上,本地变量不能从任何东西中保存。这个概念是词法范围的一部分 - 名称解析方法在动态和/或纯粹的全局范围内具有一些优点(以及缺点,如果你喜欢)。

性能的根源在于Lua locals只是堆栈槽,由整数偏移量索引,在编译时计算一次(即在load()处)。但是全局变量确实是全局表的关键,这是非常常规的表,因此任何访问都是非预先查找的。所有这些都取决于实现细节,并且可能因不同语言甚至实现而有所不同(正如有人已经指出的那样,LuaJIT能够优化很多东西,所以YMMV)。

  

现在我想知道这个概念的细节;技术上如何工作,代码的某些部分可以访问,其他部分不能访问?表演有多么适合?

从技术上讲,在5.1全局变量中是一个特殊的表,它具有访问它的特殊操作码,并且5.2删除了全局操作码并为每个函数引入了_ENV upvalue。 (我们称之为全局变量的实际上是环境变量,因为查找进入函数的环境,可以设置为除了"全局表格以外的值,但是不要改变术语上的术语。飞)。因此,用5.2术语来说,任何全局只是全局表中的一个键值对,可以通过词法范围的变量在每个函数中访问。

现在关于当地人和词汇范围。如您所知,局部变量是堆栈槽。但是如果我们的函数使用外部范围的变量呢?在这种情况下,会创建一个包含变量的特殊块,它将变为 upvalue 。 Upvalue是一种指向原始变量的无缝指针,可以防止它在范围结束时被破坏(当您逃离范围时,局部变量通常不再存在,对吧?)。

  

但主要的问题是:让我们提一下var bazinga ="太酷了。"并希望从某个地方改变它。由于字符串是公开的,我可以很容易地做到这一点。但是现在,如果它被声明为本地且我超出了范围,那么为了获得访问权限需要做出哪些性能努力,如果我通过X函数切换变量:.....

     

太过分了,局部变量保持了更高的性能以及为什么?

在你的代码片段中,它不是一个传递到调用堆栈的变量,而是一个值"太酷了。" (这是一个指向堆的指针,与所有其他垃圾收集值一样)。局部变量bazinga从未传递给任何函数,因为Lua没有被称为var-parameters(Pascal)或指针/引用(C / C ++)的概念。每次调用一个函数时,所有参数都成为它的局部变量,在我们的例子中,bazinga不是单个变量,而是在不同堆栈帧中具有相同值的一堆堆栈槽 - 相同指针进入堆,"太酷了。"该地址的字符串。因此,每个级别的调用堆栈都没有惩罚。

答案 1 :(得分:3)

在进行任何比较之前,我想提一下你的担忧可能为时过早:首先编写代码,然后对其进行分析,然后根据它进行优化。在某些情况下,事后可能很难优化事物,但这不可能是其中一种情况。

访问本地变量的速度更快,因为对全局变量的访问包括表查找(无论是_G还是_ENV)。 LuaJIT可能会优化某些表访问权限,因此差异可能不太明显。

在这种情况下,您无需交易易用性,因为您始终可以使用从函数到upvalues的访问来保持局部变量的可用性:

local myvar
function getvar() return myvar end
function setvar(val) myvar = val end

-- elsewhere
setvar('foo')
print(getvar()) -- prints 'foo'

使用getvar并不比访问myvar作为全局变量更快,但是这使您可以选择将myvar用作本地,并且仍可以从其他地方访问它文件(这可能是你希望它成为全局变量的原因)。

答案 2 :(得分:1)

你可以用os.clock()自己测试locals vs globals的性能。以下代码在虚拟机内运行的2,8 Ghz四核上进行了测试。

-- Dedicate memory:
local start = os.clock()
local timeend = os.clock()
local diff = timeend - start
local difflocal = {}
local diffglobal = {}

local x, y = 1, 1 --Locals
a, b = 1, 1 -- Globals

-- 10 tests:
for i = 0, 10, 1 do
    -- Start
    start = os.clock()
    for ii = 0, 100000, 1 do
        y = y + ii
        x = x + ii
    end
    timeend = os.clock()
    -- Stop

    diff = (timeend - start) * 1000
    table.insert(difflocal, diff)

    -- Start
    start = os.clock()
    for ii = 0, 100000, 1 do
        b = b + ii
        a = a + ii
    end
    timeend = os.clock()
    -- Stop

    diff = (timeend - start) * 1000
    table.insert(diffglobal, diff)
end
print(a)
print(b)
print(table.concat(difflocal, " ms, "))
print(table.concat(diffglobal, " ms, "))

打印:

55000550001
55000550001
2.033 ms, 1.979 ms, 1.97 ms, 1.952 ms, 1.914 ms, 2.522 ms, 1.944 ms, 2.121 ms, 2.099 ms, 1.923 ms, 2.12
9.649 ms, 9.402 ms, 9.572 ms, 9.286 ms, 8.767 ms, 10.254 ms, 9.351 ms, 9.316 ms, 9.936 ms, 9.587 ms, 9.58