Lua "class" performance
-- Plain function for baseline | |
local func = function(x) | |
return x | |
end | |
-- Closure | |
local IClass = function(id) | |
local foo = function() | |
return id | |
end | |
local bar = function() | |
local v, err = foo() | |
if err then | |
error("Failure") | |
return nil, err | |
end | |
if not v then return false end | |
return true | |
end | |
return { | |
id = id, | |
foo = foo, | |
bar = bar, | |
} | |
end | |
-- Metatables (similar to JS prototype) | |
local MTClass_mt = { | |
__index = { | |
foo = function(self) | |
return self.id | |
end, | |
bar = function(self) | |
local v, err = self:foo() | |
if err then | |
error("Failure") | |
return nil, err | |
end | |
if not v then return false end | |
return true | |
end, | |
} | |
} | |
local MTClass = function(id) | |
local obj = { | |
id = id, | |
} | |
setmetatable(obj, MTClass_mt) | |
return obj | |
end | |
-- penlight.Class - first variation | |
local PLClass1 = class() | |
function PLClass1:_init(id) | |
self.id = id | |
end | |
function PLClass1:foo() | |
return self.id | |
end | |
function PLClass1:bar() | |
local v, err = self:foo() | |
if err then | |
error("Failure") | |
return nil, err | |
end | |
if not v then return false end | |
return true | |
end | |
-- penlight.Class - second variation | |
class.PLClass2({ | |
_init = function(self, id) | |
self.id = id | |
end, | |
foo = function(self) | |
return self.id | |
end, | |
bar = function(self) | |
local v, err = self:foo() | |
if err then | |
error("Failure") | |
return nil, err | |
end | |
if not v then return false end | |
return true | |
end, | |
}) | |
local timeit = function(call, multiplier) | |
local million = 1000000 | |
multiplier = multiplier or 10 | |
local timeone = function(amount, name, Class) | |
local sts = os.clock() | |
for i = 1, amount do Class() end | |
print(string.format("%s: %d calls/sec", name, amount/(os.clock() - sts))) | |
end | |
local timeone_with_call = function(amount, name, Class, callback) | |
local sts = os.clock() | |
for i = 1, amount do callback(Class(42)) end | |
print(string.format("%s: %d calls/sec", name, amount/(os.clock() - sts))) | |
end | |
if call then timeone = timeone_with_call end | |
local msg = "Benchmarking initialization ..." | |
if call then | |
msg = "Benchmarking initialization + invocation ..." | |
end | |
print(msg) | |
local dot = function(c) | |
local id = c.id; c.foo(); c.bar() | |
end | |
local colon = function(c) | |
local id = c.id, c:foo(), c:bar() | |
end | |
-- Additional multiplier since these two are fast | |
local amount = multiplier * 1000 * million | |
timeone(amount, "Func", func, function() end) | |
timeone(amount, "Metatable", MTClass, colon) | |
local amount = multiplier * million | |
timeone(amount, "Closure", IClass, dot) | |
timeone(amount, "PLClass1", PLClass1, colon) | |
timeone(amount, "PLClass2", PLClass2, colon) | |
end | |
return { | |
timeit = timeit, | |
} |
import time | |
def func(x): | |
return x | |
class Klass: | |
def __init__(self, id): | |
self.id = id | |
def foo(self): | |
return self.id | |
def bar(self): | |
id = self.foo() | |
if not id: | |
raise Exception() | |
return True | |
def closure(id): | |
def foo(): | |
return id | |
def bar(): | |
id = foo() | |
if not id: | |
raise Exception() | |
return True | |
return { | |
"id": id, | |
"foo": foo, | |
"bar": bar, | |
} | |
def time_init(amount, klass, name): | |
sts = time.monotonic() | |
for i in range(amount): | |
klass(42) | |
print("{}: {} ops/sec".format(name, int(amount / (time.monotonic() - sts)))) | |
def time_init_access(amount, klass, name, accessor): | |
sts = time.monotonic() | |
for i in range(amount): | |
accessor(klass(42)) | |
print("{}: {} ops/sec".format(name, int(amount / (time.monotonic() - sts)))) | |
amount = 10_000_000 | |
print("Benchmarking init") | |
time_init(10 * amount, func, "Func") | |
time_init(amount, Klass, "Class") | |
time_init(amount, closure, "Closure") | |
print("Benchmarking init+invoke") | |
time_init_access(amount, Klass, "Class", lambda o: (o.id, o.foo(), o.bar())) | |
time_init_access(amount, closure, "Closure", lambda o: (o["id"], o["foo"](), o["bar"]())) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment