This has been removed, making a new topic since the module has been changed enough for me to believe it is way different than what was presented here.
Added some documentation for the functions this module has on GitHub here.
Ok thanks. Removed from the model.
Don’t be one of those people;
Also I’m pretty sure FastSpawn is not related, most signal modules handle signals using BindableEvents, like you showed, which are slower, and less optimized.
Do you have reliable sources to back up that information? I’ve ran a quick benchmark firing standard BindableEvent
s, your signal module, and NevermoreEngine’s signal module.
Nevermore’s Signal does 0.0035295000416227
Your signal does 0.005104299983941
Standard
BindableEvent
does 0.0046025000046939My specs are:
CPU: Intel i3-9100F 3.6 GHz
GPU: AMD Radeon RX 550 2GB
RAM: HyperX Fury 8GB 2400 MHz
This:
btw, for benchmarks you should wait about 5 seconds or more before running code, start up makes benchmarking weird.
Anyways thanks for giving me an idea on benchmarks (I was trying to calculate those stupid numbers…)
Can you try also connecting some functions? If you just use :Fire() with no connected functions nothing will be really calculated, since it’s just a for loop.
Hey, I tried with these scripts:
local Signal = require(game.ServerScriptService.Signal)
local signaler = Signal.new()
signaler:Connect(function()
end)
wait(10)
local start = os.clock()
for i = 1, 100000 do
signaler:Fire()
end
print(os.clock() - start)
–
local Signal = require(game.ServerScriptService.NeverMore)
wait(10)
local signaler = Signal.new()
signaler:Connect(function()
end)
local start = os.clock()
for i = 1, 100000 do
signaler:Fire()
end
print(os.clock() - start)
And the results for me were:
In this case, I ran both twice, and got their average. I only did it twice, but I don’t think more would change much.
I didn’t try with “pure” BindableEvents here, how ever, because NeverMore’s signal api is already small enough, I don’t think that would have impacted it.
Here it is waiting 5 seconds and connecting the event:
Nevermore does 0.066512100049295
Your signal does 0.068769700010307
BindableEvent
does 0.04701770003885
If I haven’t messed up anything, BindableEvent
is faster than both while Nevermore’s signal’s faster than yours.
Also I’ve read through your code and you’ve kept the coroutine concept, but the rest you’ve changed (2 tables for assigning __index?)
???
Yeah um, Connections run in “Coroutine” just like normal events. Of course it’s a bit different internally, but it is a form of coroutine.
Hm, and what are you talking about assigning __index twice? Can you show me that so I can fix it?
I think this is very dependant of hardware. Mine had completely different results like I showed.
My specs are:
AMD Athlon 3000G with Radeon Vega Graphics 3.50GHZ, 4 cores.
8 gigs of ram, 2 dedicated to integrated graphics, which leaves 6.
idk aaaaa 128GB SSD with a 1TB HDD, I guess.
I meant having 3 tables (I thought it was 2) for OOP:
You could’ve done
Signal._index = Signal
then just assign to the metatable in the constructor:
return setmetatable({
_connections = {}
}, Signal)
and for the rest you could’ve kept that information in self
Also, table.clear()
doesn’t free memory, and most likely (not sure) doesn’t get garbage collected
You can assign it to nil.
I can make a PR if you’d like to :DD
I don’t like using Bindables in my opnion. They’re slower, and for what I’m using it for, coroutines are fine. The only problems with coroutines being that they don’t error if you don’t wrap it in a pcall.
I don’t see any purpose of utilizing data-structures other than the standard dynamic arrays or dictionaries when making a custom signal, but good advice I guess.
I did. The other link I’m too dumb to understand, sorry.
If you want to optimize your code with data-structures, I would recommend only doing so when handling a large amount of input or when your code is handling some heavy work. Otherwise, it would just lead to overcomplication and a negligible speed boost.
With a custom signal module it is very unlikely to have to do any heavy work internally.
Why are data structures so important in this topic? Well it is about concurrency. If your game consists of tens of thousands of signals and you are expecting to disconnect and connect signals thousands of times a second, it becomes a necessity worth considering. This was the case for loleris (for example).
If we are on about negligible performance boosts, this whole library is very unnecessary. This one is a copy of the second signal class of the featured reply that I attached. I know its shortcomings. You are giving up solid safety for little performance boosts if any. Hence, if you are just trying to pursue speed, this is how you do it. If you are trying to develop a solid signal class library? Use bindables.
Could you elaborate more on what data-structure you used in your implementation and how it fixes the thread concurrency issues?