Best way to update multiple objects?

I have many objects that I need to update and the faster the better. The problem is that if I use RunService:Heartbeat() to update them, the next event will fire before the previous update has not finished - which leads to bugs.
If I use a while loop or RunService:Heartbeat:Wait() Loop, then there is a long delay between updates since there are many objects.
What can I do as an alternative?

Potentially using coroutines to update each object individually in a while loop may help, but I am afraid it causes lag.
For example:

while RunService:Heartbeat:Wait() do
    coroutine.wrap(function()
        obj1:Update()
    end)()
    coroutine.wrap(function()
        obj2:Update()
    end)()
    obj3:Update()
end

EDIT: It does NOT need to run every frame, but the faster the better.

1 Like

Why not use a for loop and have it be updated with Heartbeat?

local ToUpdate = { ... }

local function UpdateThings()
    for _, Thing in next, ToUpdate do
        coroutine.wrap(Thing.Update)(Thing)
    end
end

RunService.Heartbeat:Connect(UpdateThings)

Does this really need to be ran every frame? I feel like just creating 1 coroutine and 1 inf loop nested in would be better performance wise

1 Like

Hey, thanks for replying. Isn’t this the same as I wrote? I just have unique objects that aren’t in array so I didn’t bother writing one in the example. Also what’s the point of using a coroutine if it’s already inside of a Heartbeat loop?

Just asking but what’re u updating?

In simpler steps, yeah. It just takes out the while loop and introduces the for loop to prevent re-writing multiple coroutines for each obj:Update().

I assumed you had used coroutine.wrap perhaps due to obj:Update() having a yielding method.

Okay my issue is that if I use Heartbeat, then the next Heartbeat will run before the previous one could finish. What I mean:

Heartbeat calls obj:Update()
    obj is updating(1)...
    obj is updating(1)...
    obj is updating(1)...
Heartbeat is fired again and calls obj:Update() while the first call of update has not finished
    obj is updating(1)...
    obj is updating(2)...
    obj is updating(1)...
    etc

If I instead use a while loop then my problem is that it takes too long for every object to update before the next iteration happens.

first iteration of loop:
    for i, object in pairs(objects) do
        object:Update() --Assume it takes roughly half a second
    end

there is a long delay between every iteration which in my case is more like 0.05 of a second but still long
what would be some alternatives to both of these?

It executes the code on the same rendered step. You shouldn’t have to worry about that.

1 Like

You could always use some debounces to make sure your objects arent updated again before the update before has finished.

1 Like

Hello,

If you’re doing this on the server, updating things on the server faster than Heartbeat is not very good.
If you’re running this on the client however you could bind it to RenderStepped, making it so it’s part of the process of rendering and will assure that it finishes before going to the next frame. Though if you’re telling us it is expensive to run whatever you’re trying to run then I’d be more concerned at the :Update method that you’ve made, you should share that part of the code to see how we can improve the speed of it.

Unless :Update yields, please do not use coroutines inside of a loop like that it’s not the best thing to do, especially if you have “a lot of objects”. You’re just avoiding the problem (:Update being slow)

2 Likes

Yes I am doing this on the server, the Update functions themselves aren’t that expensive and they aren’t yielding functions either. My issue is that Heartbeat is too fast (fires before every the Update functions can finish), and while loops are too slow. Look at my reply to TheeDeathCaster for more detail. Thanks a lot though.

Why would it roughly take half a second for each then? If it’s not yielding then it’s expensive / if it’s not expensive then it’s yielding, nothing should take 0.5s

that was just an example, i mentioned my code takes way less time (maybe 0.02 - 0.05 of a second) but the functions are too long to post here nor do i know the exact time it takes

Running that script faster than what it can by using coroutines will eventually just cause server slowdowns if it cannot complete full cycles every heartbeat. 0.02-0.05 seconds is still relatively long for 1 method. The goal is not to make your script cycle faster, it’s to optimize your :Update function so it doesn’t cause massive server slowdowns and can complete the cycles properly.

You should provide the code used in :Update and the amount of objects you update

1 Like

I have around 8 unique objects from different classes, before I do that maybe I can give another example. What would work for me, is if I updated each object in its own while loop:

while RunService:Heartbeat:Wait() do
    object1:Update()
end)

while RunService:Heartbeat:Wait() do
    object2:Update()
end)
etc...

Updating every object in one while loop also works and it still does it very fast, but there are some noticeable delays that are avoidable when I use Heartbeat, but Heartbeat causes bugs.

while RunService:Heartbeat:Wait() do
    object1:Update()
    object2:Update()
end)

I see, you can then instead wrap your while loops in coroutines (outside) and they will all fire every Heartbeat.

local objects = {};

for _, obj in objects do
    coroutine.wrap(function()
        while RunService:Heartbeat:Wait() do
            obj:Update();
        end)
    end)();
end

Though I do not know how much this will impact server performance as I don’t know how harsh your Update function is still.

Making a coroutine outside will be better for memory and reduce some load over time, but will be slower than wrapping every :Update inbetween a coroutine.

For future reference, this is a way better alternative and you should really look at this: Parallel Luau | Documentation - Roblox Creator Hub

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