Globals很糟糕,这会以任何方式提高性能吗?

时间:2013-02-14 18:12:18

标签: lua luajit

我在LuaJIT工作,把我所有的库和诸如此类的东西存储在“foo”中,如下所示:

foo = {}; -- The only global variable
foo.print = {};
foo.print.say = function(msg) print(msg) end;
foo.print.say("test")

现在我想知道,是否会使用metatables并保持所有图书馆的本地帮助?或者没关系。我想到的是:

foo = {};
local libraries = {};

setmetatable(foo, {
    __index = function(t, key)
        return libraries[key];
    end
});

-- A function to create a new library.
function foo.NewLibrary(name)
    libraries[name] = {};

    return libraries[name];
end;

local printLib = foo.NewLibrary("print");

printLib.say = function(msg) print(msg) end;

-- Other file:
foo.print.say("test")

我现在没有真正的基准测试工具,但是保留本地表中库的实际内容会提高性能吗?即使是最轻微的?

我希望我对此有所了解,基本上我想知道的是:性能方面的第二种方法更好吗?

如果有人可以链接/详细解释Lua中如何处理全局变量,这可以解释这一点也很好。

2 个答案:

答案 0 :(得分:2)

  

现在没有真正的工具来对此进行基准测试

当然可以。

local start = os.clock()
for i=1,100000 do -- adjust iterations to taste
    -- the thing you want to test
end
print(os.clock() - start)

凭借性能,您几乎总是希望进行基准测试。

  

是否会保持本地表中库的实际内容能够提高性能?

与第一个版本的代码相比?理论上没有。

你的第一个例子(剥离了不必要的瑕疵):

foo = {}
foo.print = {}
function foo.print.say(msg)
    print(msg)
end

要获得打印功能,需要进行三次表查找:

  1. 索引_ENV与“foo”
  2. 使用“print”
  3. 索引foo
  4. 索引foo.print表格中有“说”。
  5. 你的第二个例子:

    local libraries = {}
    libraries.print = {}
    function libraries.print.say(msg)
        print(msg)
    end
    
    foo = {}
    setmetatable(foo, {
        __index = function(t, key)
            return libraries[key];
        end
    });
    

    要获得打印功能,现在需要进行五次表格查找以及其他额外工作:

    1. 索引_ENV与“foo”
    2. 使用“print”
    3. 索引foo
    4. Lua发现结果为nil,检查foo是否有metatable,找到一个
    5. index metatable with“__ index”
    6. 检查结果是否是表或函数,Lua发现它是一个函数,所以用键调用它
    7. 使用“print”
    8. 索引libraries
    9. 使用“说”
    10. 索引print

      其中一些额外的工作是在C代码中完成的,所以它会比在Lua中实现的更快,但肯定会花费更多的时间。

      使用上面显示的循环进行基准测试,第一个版本大约是香草Lua中第二个版本的两倍。在LuaJIT中,两者的速度完全相同。显然,在LuaJIT中,差异会在运行时得到优化(这非常令人印象深刻)。只是说明基准测试的重要性。


      附注:Lua允许您提供__index的表格,这将导致与您的代码等效的查找:

      setmetatable(foo, { __index = function(t, key) return libraries[key] end } )
      

      所以你可以写:

      setmetatable(foo, { __index = libraries })
      

      这也恰好更快。

答案 1 :(得分:1)

以下是我编写模块的方法:

-- foo.lua
local MyLib = {}

function MyLib.foo()
    ...
end

return MyLib

-- bar.lua
local MyLib = require("foo.lua")
MyLib.foo()

请注意,return MyLib不在函数中。 require捕获此返回值并将其用作库。这样,就没有全局变量。