Is wait needed in a for loop?

In a infinite loop, you need to wait a certain amount of time otherwise your game might freeze, but should I use wait() in a for loop? Is it required? Does it have possibilities of crashing like it would if I didn’t wait a certain amount of time in a infinite loop?

Here’s an example:

for i,v in pairs(workspace:GetChildren()) do
     print(v)
end

and another one:

for i = 1,20 do
     print(i)
end

So, is a wait() required in these loops at all? If not, is there still a possibility of it crashing like a infinite loop without a wait()?

6 Likes

Waiting isn’t necessarily required in any loops. Even in while loops if they have a proper condition set.

Waiting inside a for loop however, isn’t necessary at all! Unless you’re doing math.huge for some reason. As the loop is finite and will end after a certain amount of times the loop has run itself through, and without a wait(), depending on efficient the script is. When running through the loop, even thousands upon thousands of times, it will be almost instantaneous.

2 Likes

Spoiler (for lazy people)!! → TLDR: No, you likely don’t need to.

The reason that you experience the “freeze” is because the main lua thread is being entirely used up by your loop.

If you have an unreasonable amount of elements to iterate over (lets say 10^6) you will notice a short performance drop. This can be inefficiently solved by using a yield every iteration, however your code that ran in 1 second (for the sake of argument I’m going to use 1 second) will now take around 30000 seconds. (10^6 * 0.03)

If you are iterating over large sets of data I suggest unrolling your loop in a few ways.
1] Decrease the amount of iterations and increase the amount of times you run the given line of code (without a loop)
2] Do #1 but with a loop and some sort of yield every x iterations of the total y iterations.

Examples

1] Unrolled Loop

Where you might normally have 5000 iterations, instead do 1000 iterations and repeat the code 5 times.

for i = 1, 1000, 5 do
    f(i)
    f(i + 1)
    f(i + 2
    f(i + 3)
    f(i + 4)
end

2] “Stacked” loop (I don’t know the correct terminology)

Where you might have 5000 iterations, do only 5 iterations of 1000 iterations (or the other way around, but that is slower)

for i = 1, 5 do
    for j = 1, 1000 do

    end
    yield() --// arbitrary "wait" function
end
7 Likes

I tend to add waits if I don’t really need the loop to be running constantly.

For example, if I were checking the player’s walkspeed for something (and didn’t want to use an event) I might structure my loop like

while wait(.1) do
    if Player.WalkSpeed == somenumber then
        --Code
    end
end

For the purposes of my code, it’s probably fine if I’m just checking every .1 seconds, since I’m still checking 10 times each second. It would be probably unlikely that the player’s speed is going to hit whatever number I’m looking for, and then suddenly change from it within .1 seconds which would cause it to maybe be undetected. This is just me though trying to be frugal/efficient with my code (and yeah, it could make a slight difference [or large one, if I was executing a lot of code in a loop over and over] to someone with a worse off PC)

1 Like

It depends on what you are using the loop for, as @EpicMetatableMoment explained really well.

But in my experience I’ve found that if you find yourself needing to add wait()'s in a loop that isn’t supposed to be infinite, you’re probably doing something wrong. You might want to use one of the optimization methods mentioned above, or re-structure your code if there is a way that doesn’t require such a huge iteration. (Often times there is a way.)

And as a proponent of event-driven programming I will suggest this: If there is a way that allows you to replace an interminable loop with an event-based system, use it.
For example:

while (true) do
    if (#game.Players:GetPlayers() >= 2) then
        status = "Beginning game"
    else
        status = "Waiting for more players"
    end
    wait()
end

Can be replaced with:

function check()
    if (#game.Players:GetPlayers() >= 2) then
        status = "Beginning game"
    else
        status = "Waiting for more players"
    end
end
game.Players.PlayerAdded:Connect(check)
game.Players.PlayerRemoving:Connect(check)

Instead of constantly running the interior code, it will listen for those PlayerAdded and PlayerRemoving events, since the logic in this example is only necessary to be used when the number of players changes.

2 Likes

how would i do this with a for i, v in pairs() loop?

1 Like