1
0
mirror of https://github.com/kepler155c/opus synced 2025-01-14 09:25:42 +00:00

reduce coroutine creation

This commit is contained in:
kepler155c@gmail.com 2018-11-22 13:52:45 -05:00
parent 39e8307511
commit d5896ca873

View File

@ -1,4 +1,5 @@
local os = _G.os local os = _G.os
local table = _G.table
local Event = { local Event = {
uid = 1, -- unique id for handlers uid = 1, -- unique id for handlers
@ -6,8 +7,29 @@ local Event = {
types = { }, -- event handlers types = { }, -- event handlers
timers = { }, -- named timers timers = { }, -- named timers
terminate = false, terminate = false,
free = { },
} }
-- Use a pool of coroutines for event handlers
local function createCoroutine(h)
local co = table.remove(Event.free)
if not co then
co = coroutine.create(function(_, ...)
local args = { ... }
while true do
h.fn(table.unpack(args))
h.co = nil
table.insert(Event.free, co)
args = { coroutine.yield() }
h = table.remove(args, 1)
h.co = co
end
end)
end
h.primeCo = true -- TODO: fix...
return co
end
local Routine = { } local Routine = { }
function Routine:isDead() function Routine:isDead()
@ -24,18 +46,20 @@ function Routine:terminate()
end end
function Routine:resume(event, ...) function Routine:resume(event, ...)
--if coroutine.status(self.co) == 'running' then
--return
--end
if not self.co then if not self.co then
error('Cannot resume a dead routine') error('Cannot resume a dead routine')
end end
if not self.filter or self.filter == event or event == "terminate" then if not self.filter or self.filter == event or event == "terminate" then
local s, m = coroutine.resume(self.co, event, ...) local s, m
if self.primeCo then
if coroutine.status(self.co) == 'dead' then -- Only need self passed when using a coroutine from the pool
s, m = coroutine.resume(self.co, self, event, ...)
self.primeCo = nil
else
s, m = coroutine.resume(self.co, event, ...)
end
if self:isDead() then
self.co = nil self.co = nil
self.filter = nil self.filter = nil
Event.routines[self.uid] = nil Event.routines[self.uid] = nil
@ -83,8 +107,12 @@ end
function Event.off(h) function Event.off(h)
if h and h.event then if h and h.event then
for _,event in pairs(h.event) do for _,event in pairs(h.event) do
local handler = Event.types[event][h.uid]
handler:terminate()
Event.types[event][h.uid] = nil Event.types[event][h.uid] = nil
end end
elseif h and h.co then
h:terminate()
end end
end end
@ -107,7 +135,12 @@ local function addTimer(interval, recurring, fn)
end end
function Event.onInterval(interval, fn) function Event.onInterval(interval, fn)
return addTimer(interval, true, fn) return Event.addRoutine(function()
while true do
os.sleep(interval)
fn()
end
end)
end end
function Event.onTimeout(timeout, fn) function Event.onTimeout(timeout, fn)
@ -183,7 +216,7 @@ local function processHandlers(event)
for _,h in pairs(handlers) do for _,h in pairs(handlers) do
if not h.co then if not h.co then
-- callbacks are single threaded (only 1 co per handler) -- callbacks are single threaded (only 1 co per handler)
h.co = coroutine.create(h.fn) h.co = createCoroutine(h)
Event.routines[h.uid] = h Event.routines[h.uid] = h
end end
end end