Heartbeat handle help

Should it be improved? I’m a new developer, and I’ve heard that having one connection is better than multiple connections. (google translate)

Handler:

local RunService = game:GetService("RunService")

local __public = {}
local __private = {}

__private.connection = nil
__private.functions = {}

function __public.Main()
	__private.connection = RunService.Heartbeat:Connect(function(deltaTime)
		for _, func in pairs(__private.functions) do
			coroutine.wrap(func)(deltaTime)
		end
	end)
end

function __public:Connect(funcName, func)
	__private.functions[funcName] = func
end

function __public:Disconnect(funcName, func)
	__private.functions[funcName] = nil
end

return table.freeze(__public)

Example:

local Heartbeat = require(script.Parent.Heartbeat)

function Main()
	Heartbeat:Connect("Test", function(deltaTime)
		print("Test")
	end)
end

return { Main = Main }
3 Likes

Yes, your code should be improved for better error handling, avoiding unnecessary coroutines, and improving readability and efficiency.

3 Likes

That’s true - to a very small degree.
Connections do consume a small amount of memory, so you shouldn’t really be creating too much of them.

In this case though, this is an exaggeration.

In practice, your game will not make as many connections (for RunService at least) as it would to consume a huge part of a server’s memory.

It’s why I think this is just overkill. Just stick with what RunService provides you, and you’ll be fine.

3 Likes

I’m assuming you’re coming from another platform? The way you format your code, seems strangely reminiscent of C#. But that’s a bit of an aside.

Getting on topic, the question of whether less connections should be preferred over more connections, doesn’t have such a clear cut answer. Thread objects (the objects which represent coroutines in Lua/u) are quite cheap in memory. Having multiple threads which are static is fine. The danger is inadvertently creating lots of temporary threads on the frame, which consistently put otherwise avoidable strain on the garbage collector. Roblox’s implementation of Connections is smart, in that ordinarily, connections will recycle the same thread to handle callbacks in. Where this falls apart however, is when the connected function yields. If the function yields, there’s no guarantee that the thread will be available to handle the next callback, and so rather than recycling the same thread, the connection creates a new one.

Here, by merging together callbacks into the same connection, you take functions which may have otherwise ran in the same thread, and guarantee that new threads will be created, by explicitly calling coroutine.wrap. Unless every one of these callbacks would have yielded anyway, this approach is undoubtedly more costly than if you had just opened separate connections for each of them.

2 Likes

Thanks so much for all the replies and comments, and I will put it to good use.

1 Like

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