2

我在 LuaJIT 工作,我所有的库和其他东西都存储在“foo”中,如下所示:

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

现在我想知道,是否会使用元表并保持所有库的本地帮助?或者这不重要。我想到的是这样的:

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 中处理全局变量,这也可以解释这一点。

4

2 回答 2

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. 使用“foo”索引 _ENV
  2. foo带有“打印”的索引表
  3. foo.print带有“say”的索引表。

你的第二个例子:

local libraries = {}
libraries.print = {}
function libraries.print.say(msg)
    print(msg)
end

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

要使用您的打印功能,现在需要进行五次表查找以及其他额外工作:

  1. 使用“foo”索引 _ENV
  2. foo带有“打印”的索引表
  3. Lua 发现结果为 nil,检查是否foo有元表,找到一个
  4. 带有“__index”的索引元表
  5. 检查结果是表还是函数,Lua发现它是一个函数,所以它用键调用它
  6. libraries带有“打印”的索引
  7. print用“say”索引表

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

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


旁注:Lua 允许您为 提供一个表__index,这将导致与您的代码等效的查找:

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

所以你可以写:

setmetatable(foo, { __index = libraries })

这也恰好要快得多。

于 2013-02-14T20:07:58.500 回答
1

这是我编写模块的方式:

-- foo.lua
local MyLib = {}

function MyLib.foo()
    ...
end

return MyLib

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

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

于 2013-09-05T21:49:37.030 回答