문제

I'm working in LuaJIT and have all my libraries and whatnot stored inside "foo", like this:

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

Now I was wondering, would using metatables and keeping all libraries local help at all? Or would it not matter. What I thought of is this:

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")

I don't really have the tools to benchmark this right now, but would keeping the actual contents of the libraries in a local table increase performance at all? Even the slightest?

I hope I made mysef clear on this, basically all I want to know is: Performance-wise is the second method better?

If someone could link/give a detailed explaination on how global variables are processed in Lua which could explain this that would be great too.

도움이 되었습니까?

해결책

don't really have the tools to benchmark this right now

Sure you do.

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

With performance, you pretty much always want to benchmark.

would keeping the actual contents of the libraries in a local table increase performance at all?

Compared to the first version of the code? Theoretically no.

Your first example (stripping out the unnecessary cruft):

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

To get to your print function requires three table lookups:

  1. index _ENV with "foo"
  2. index foo table with "print"
  3. index foo.print table with "say".

Your second example:

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

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

To get to your print function now requires five table lookups along with other additional work:

  1. index _ENV with "foo"
  2. index foo table with "print"
  3. Lua finds the result is nil, checks to see if foo has a metatable, finds one
  4. index metatable with "__index"
  5. check to see if the result is is is table or function, Lua find it's a function so it calls it with the key
  6. index libraries with "print"
  7. index the print table with "say"

Some of this extra work is done in the C code, so it's going to be faster than if this was all implemented in Lua, but it's definitely going to take more time.

Benchmarking using the loop I showed above, the first version is roughly twice as fast as the second in vanilla Lua. In LuaJIT, both are exactly the same speed. Obviously the difference gets optimized away at runtime in LuaJIT (which is pretty impressive). Just goes to show how important benchmarking is.


Side note: Lua allows you to supply a table for __index, which will result in a lookup equivalent to your code:

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

So you could just write:

setmetatable(foo, { __index = libraries })

This also happens to be a lot faster.

다른 팁

Here is how I write my modules:

-- foo.lua
local MyLib = {}

function MyLib.foo()
    ...
end

return MyLib

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

Note that the return MyLib is not in a function. require captures this return value and uses it as the library. This way, there are no globals.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top