My module seems slower?

I was basically finishing a non-metatable signal module and decided to benchmark it against existing ones. I was shocked to see that my module lost against other modules by a significant margin. I tried to find the reason in performance and metatables, but simply couldn’t. I thought it was maybe something to do with namecalls. But no.

Please, I’m desperate on finding out the actual reason behind this margin.

Here is the module:
signal.txt (2.2 KB)

Hey!

I looked it through. It is overall quite a good code. I thought about it for a while… The worst scenario could occur at the Event_Fire. You might want to instead iterate it through once, rather than shifting on the elements with table.remove. This in the very worst scenario could cause you a O(n^2) time complexity. Instead open a secondary queue in Event_Fire and that will solve the issue.

local function Event_Fire(self:Event, ...) : ()
    local queue = self._queue
    local newQueue = {}
    for i, v in ipairs(queue) do
        if type(v) == "function" then
            coroutine.resume(coroutine.create(v), ...)
            newQueue[#newQueue + 1] = v  -- keep the function event for future fires
        else
            coroutine.resume(v, ...)
            -- Thread events are run only once; do not reinsert them.
        end
    end
    self._queue = newQueue
end

There is also one more that I would point out. It is a bit more memory requiring, but would perform better than using a table.remove. That can be achieved by using a swap-and-pop technique within your Event_Pop. The order will still be preserved and that function will be faster as well rather than when using table operations and it is more cache friendly.

local function Event_Pop(self: Event, func: (...any) -> () | thread)
    -- Track the position where we write kept elements
    local keep_pos = 1
    
    -- Scan through all elements
    for scan_pos = 1, #self._queue do
        -- If the current element is NOT the one to remove, keep it
        if self._queue[scan_pos] ~= func then
            self._queue[keep_pos] = self._queue[scan_pos]
            keep_pos += 1
        end
    end
    
    -- Clear leftover elements after the last kept position
    for i = keep_pos, #self._queue do
        self._queue[i] = nil
    end
end

Fixing it didn’t do anything. The module is still 2x times slower than any other eventer.

False alarm; the deal actually was with other modules, as they didn’t properly utilize their threads, which caused them to improperly yield.

Still thanks to MapleBattle I actually changed a few things and managed to improve performance by quite a bit

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.