Passing all remotes through one instance

Hey, I wrote a basic module that basically passes all the remote data through a single remote event or function. It creates n amount of connections based on how many times you run the Remotes.Events:Connect() function.

Is this more effcient than making multiple remotes?

2

I had been curious about this before and had run into conflicting information that tended to be anecdotal rather than empirical, so I did some testing. I did client-server and server-client traffic using 100 calls to a single remote and 1 call each to 100 remotes.

The code, if interested.

Client Code:
--!strict
--//CLIENT TEST//

task.wait(10)

local replicated_storage = game:GetService("ReplicatedStorage")

local ping_remote = replicated_storage:WaitForChild("PingEvent")			--For communication outside of the test space.
local single_remote = replicated_storage:WaitForChild("SingleRemote")		--For single-remote tests.
local remotes: {RemoteEvent} =
	replicated_storage:WaitForChild("Remotes100"):GetChildren() :: any		--For multi-remote tests.

local ping_start: number
local function process_request(count: number): ()
	if count == 1 then
		ping_start = os.clock()
	elseif count == 100 then
		local stop = os.clock()
		print("TOTAL PROCESSING TIME: " .. (stop - ping_start) * 1000000 .. " microseconds.")
	end
end

single_remote.OnClientEvent:Connect(process_request)
for _, remote in ipairs(remotes) do
	remote.OnClientEvent:Connect(process_request)
end

print("PINGING SERVER.")

ping_remote:FireServer()
ping_remote.OnClientEvent:Wait()

print("RECEIVED BATON FROM SERVER")

task.wait(2)

print("CLIENT-SERVER SINGLE REMOTE")

for count = 1, 100 do
	single_remote:FireServer(count)
end

task.wait(2)

print("CLIENT-SERVER MULTIPLE REMOTES")

for index, remote in ipairs(remotes) do
	remote:FireServer(index)
end
Server Code:
--!strict
--//SERVER TEST//

local replicated_storage = game:GetService("ReplicatedStorage")

local ping_remote = replicated_storage:WaitForChild("PingEvent")			--For communication outside of the test space.
local single_remote = replicated_storage:WaitForChild("SingleRemote")		--For single-remote tests.
local remotes: {RemoteEvent} =
	replicated_storage:WaitForChild("Remotes100"):GetChildren() :: any		--For multi-remote tests.

local ping_start: number
local function process_request(_: Player, count: number): ()
	if count == 1 then
		ping_start = os.clock()
	elseif count == 100 then
		local stop = os.clock()
		print("TOTAL PROCESSING TIME: " .. (stop - ping_start) * 1000000 .. " microseconds.")
	end
end

single_remote.OnServerEvent:Connect(process_request)
for _, remote in ipairs(remotes) do
	remote.OnServerEvent:Connect(process_request)
end

ping_remote.OnServerEvent:Connect(function(player: Player): ()
	print("RECEIVED INITIALIZATION PING FROM PLAYER: " .. player.Name)
	
	task.wait(2)
	
	print("SERVER-CLIENT SINGLE REMOTE")

	for count = 1, 100 do
		single_remote:FireClient(player, count)
	end

	task.wait(2)

	print("SERVER-CLIENT MULTIPLE REMOTES")

	for index, remote in ipairs(remotes) do
		remote:FireClient(player, index)
	end
	
	task.wait(2)
	
	print("PASSING BATON TO CLIENT")
	
	ping_remote:FireClient(player)
end)

Each request was just a number from 1 to 100, in order. On receiving the “1” packet, the time would be marked, and upon receiving the “100” packet, the duration would be determined. Here is the average receivers’ processing duration of each type of request in microseconds:

Server → Client Client → Server
Single Multi Single Multi
Studio 142 μs 229 μs 242 μs 379 μs
Live 149 μs 226 μs 236 μs 515 μs

Note that fluctuating latency will have an impact on live server testing, so expect some outliers.

From these tests, it seems that fewer remotes perform better than more remotes, but this test is done in a vacuum with simple requests. Your mileage may vary depending on system complexity and whether or not using multiple remotes could gain you performance benefits in event processing (for instance, a multi-event approach may be able to take advantage of upvalues in the scope of the event handler whereas a single-remote structure is more likely to require table lookups to find everything it needs, although I’m not sure how much that would realistically net you).

In the end, though, you’re most likely too see gains in better management of the requests themselves than in the number of remotes used to deliver those requests.

2 Likes