(Archived) Signal API - For all your event needs!

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.

7 Likes

Added some documentation for the functions this module has on GitHub here.


What’s the point of this? We have FastSpawn and Signal modules already

1 Like

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.

4 Likes

Do you have reliable sources to back up that information? I’ve ran a quick benchmark firing standard BindableEvents, your signal module, and NevermoreEngine’s signal module.


Nevermore’s Signal does 0.0035295000416227

Your signal does 0.005104299983941

Standard BindableEvent does 0.0046025000046939
My specs are:
CPU: Intel i3-9100F 3.6 GHz
GPU: AMD Radeon RX 550 2GB
RAM: HyperX Fury 8GB 2400 MHz

1 Like

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.

3 Likes

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.

1 Like

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?

2 Likes

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.

1 Like

I meant having 3 tables (I thought it was 2) for OOP:
image
image
image
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
image
You can assign it to nil.
I can make a PR if you’d like to :DD

1 Like

shoreee do it I kind of want to cuz because I wanna test it out :joy:

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.

1 Like

I did. The other link I’m too dumb to understand, sorry.

That’s because I did this.

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.

1 Like

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.

1 Like

Could you elaborate more on what data-structure you used in your implementation and how it fixes the thread concurrency issues?