Optimisation is generally only necessary when Lua modules are misused or inefficient.
Important note
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." [1]
General guidelines
If for whatever reason your modules are exceeding the limit, you should then consider optimising.
Whenever possible[2]:
- Use local functions or variables
- Avoid nested functions
- Use arrays instead of tables (hashing)
- Use local variables instead of indexing tables
Simple optimisations such as copying a global function (e.g. string.match) may greatly improve performance of a module.
Tip: Use os.clock() before and after a code "chunk" and subtract the two results to evaluate the code section's performance.
String vs table concatenation
When dealing with potentially huge strings, it is more efficient to add them to a table and use table.concat rather than simply using "join" or concatenating them [3].
-- This is slower
local people = {"John", "Mary", "Parker", "Sue", "Anonymous", "..."}
local text = ""
for i = 1, #people do
if i > 1 then
text = text .. ", "
end
text = text .. people[i]
end
print(text)
-- This is faster
local people = {"John", "Mary", "Parker", "Sue", "Anonymous", "..."}
local text = table.concat(people, ", ")
print(text)
Use tables for SQL-IN alike compares
This means that instead of having a lot of if statements a better alternative is to put them all in a set-like table[4]. For example, this is a typical if
structure:
local function foo(value)
if value == "foo" or value == "bar" or value == "baz" or value == "qux"
or value == "lorem" or value == "ipsum" then
return "something"
end
return "something else"
end
... and this is a more efficient, table-based one:
local function foo(value)
local validValues = {
foo = true,
bar = true,
baz = true,
qux = true,
lorem = true,
ipsum = true
}
if validValues[value] then
return "something"
end
return "something else"
end
Note that you can use any truthy value, instead of just true
.
Templates
Using too many template transclusions in a single page is one common problem that affects the speed of lua. Each invocation will count towards the lua limit.
There are multiple techniques to overcome this:
- Consolidate - move all code to a module, and restructure it to only be called fewer times
- Rewrite the code to be more efficient.
Change template "databases" into data modules
Making templates databases causes a lot of issues such as becoming cumbersome to use, and slower if they use parser functions. One idea is adding them to a module, as described in Lua templating/Converting Wikitext templates.
If the template is used several times on a page, consider using mw.loadData to load its data, instead of require:
local data = mw.loadData("Module:Mystuff")
return data[frame.args[1]]
Avoid multiple invocations to the same module
Instead of this for example:
local p = {}
function p.showpopulation(frame)
local pop = {['china'] = 50, ['australia'] = 20, ['ghana'] = 10}
return pop[frame.args[1]]
end
return p
{{#invoke:mymodule|showpopulation|china}} {{#invoke:mymodule|showpopulation|australia}} {{#invoke:mymodule|showpopulation|ghana}}
Do this:
local p = {}
function p.showpopulation(frame)
local pop = {['china'] = 50, ['australia'] = 20, ['ghana'] = 10}
local args = frame.args
return pop[args[1]] .." ".. (pop[args[2]] or "") .. " " ..(pop[args[3]] or "")
end
return p
{{#invoke:mymodule|showpopulation |china |australia |ghana }}
References
- ↑ The fallacy of premature optimization http://ubiquity.acm.org/article.cfm?id=1513451
- ↑ http://www.lua.org/gems/sample.pdf
- ↑ http://www.lua.org/pil/11.6.html
- ↑ http://stackoverflow.com/a/12865406