【问题标题】:local VS global in lualua中的本地VS全局
【发布时间】:2014-10-02 05:34:34
【问题描述】:

每个来源都同意这一点:

the access to local variables is faster than to global ones

在实际使用中,主要区别在于如何处理变量,因为它受限于范围,无法从代码的任何位置访问。

理论上,局部变量可以避免非法更改,因为它不能从错误的位置访问,甚至更好的是,查找 var 的性能要高得多。

现在我想知道这个概念的细节; 它在技术上是如何工作的,代码的某些部分可以访问,而其他部分则不能? 性能提升到什么程度?

但主要问题是: 让我们提一下,我有一个 var bazinga = "Socool." 并想从某个地方更改它。 由于字符串是公开的,我可以很容易地做到这一点。 但是现在,如果它被声明为本地并且我超出了范围,那么如果我通过这样的 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

到了极点,局部变量的性能越来越好,为什么?

我问你,由于维护将对象移交给许多功能的代码变得一团糟,我想知道这是否真的值得。

【问题讨论】:

    标签: performance parameters lua global local


    【解决方案1】:

    理论上,局部变量可以避免非法更改,因为它不能从错误的位置访问,甚至更好的是,查找 var 的性能要高得多。

    局部变量在实际意义上不是从任何东西中保存的。这个概念是词法作用域的一部分——与动态和/或纯粹的全局作用域相比,这种名称解析方法具有一些优点(如果您愿意,也有一些缺点)。

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

    现在我想知道这个概念的细节;它在技术上是如何工作的,代码的某些部分可以访问,而其他部分则不能?性能提升到什么程度?

    从技术上讲,在 5.1 中 globals 是一个特殊的表,其中包含访问它的特殊操作码,而 5.2 删除了全局操作码并为每个函数引入了 _ENV upvalue。 (我们所说的全局变量实际上是环境变量,因为查找进入函数的环境,可能设置为“全局表”以外的值,但我们不要即时更改术语)。所以,用 5.2 的术语来说,任何全局都只是全局表中的一个键值对,每个函数都可以通过词法范围变量访问它

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

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

    到了极点,局部变量的性能越来越好,为什么?

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

    【讨论】:

      【解决方案2】:

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

      访问局部变量更快,因为访问全局变量包括查表(无论是在_G 还是在_ENV)。 LuaJIT 可能会优化某些表访问,因此差异可能不太明显。

      在这种情况下,您无需牺牲访问的便利性,因为您始终可以使用从函数到上值的访问来保持局部变量可用:

      local myvar
      function getvar() return myvar end
      function setvar(val) myvar = val end
      
      -- elsewhere
      setvar('foo')
      print(getvar()) -- prints 'foo'
      

      使用getvar 不会比将myvar 作为全局变量访问更快,但这为您提供了将myvar 用作本地变量的选项,并且仍然可以从其他文件访问它(这可能就是为什么你会希望它是一个全局变量)。

      【讨论】:

        【解决方案3】:

        您可以使用 os.clock() 自己测试局部变量与全局变量的性能。以下代码在虚拟机内运行的 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-19
          • 2018-12-08
          • 2020-12-21
          • 1970-01-01
          • 2012-03-01
          • 2012-08-08
          • 2022-01-21
          • 1970-01-01
          相关资源
          最近更新 更多