Skip to content

Instantly share code, notes, and snippets.

@haizaar
Last active May 11, 2019 14:40
Show Gist options
  • Save haizaar/efcc083eb048d915a774ca901b0047ac to your computer and use it in GitHub Desktop.
Save haizaar/efcc083eb048d915a774ca901b0047ac to your computer and use it in GitHub Desktop.
Lua "class" performance
-- 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
print("Checking correctness")
local c = OClass(5)
print("OClass: id=", c.id, " foo()=", c.foo(), " bar()=", c.bar())
local c = MTClass(5)
print("MTClass: id=", c.id, " foo()=", c:foo(), " bar()=", c:bar())
local c = IClass(5)
print("IClass: id=", c.id, " foo()=", c.foo(), " bar()=", c.bar())
local c = PLClass1(5)
print("PLClass1: id=", c.id, " foo()=", c:foo(), " bar()=", c:bar())
local c = PLClass2(5)
print("PLClass2: id=", c.id, " foo()=", c:bar(), " bar()=", c:bar())
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, "Baseline", OClass, dot)
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
class A:
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
amount = 100_000_000
sts = time.monotonic()
for i in range(amount):
a = A(42)
print("Init: {} ops/sec".format(int(amount / (time.monotonic() - sts))))
sts = time.monotonic()
for i in range(amount):
a = A(42)
a.foo()
a.bar()
print("Init: {} ops/sec".format(int(amount / (time.monotonic() - sts))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment