Prevent for loop exhausted execution time?

So I wrote a script that welds parts inside voxelGroup into another part called Terrain:

local main = workspace.Terrain
for _, child in ipairs(voxelGroup:GetChildren()) do
	if child:IsA("BasePart") then
		if child ~= main then
			local weld = Instance.new("WeldConstraint")
			weld.Part0 = main
			weld.Part1 = child
			weld.Parent = child
			child.Anchored = false
			workspace.count.Value += 1
		end
	end
end

the problem is that I have lots of parts like 90000+ of them and the script would just randomly exhaust the execution time (sometimes it exhaust, sometimes it doesn’t), I tried adding task.wait() like this:

local main = workspace.Terrain
for _, child in ipairs(voxelGroup:GetChildren()) do
	if child:IsA("BasePart") then
		if child ~= main then
			local weld = Instance.new("WeldConstraint")
			weld.Part0 = main
			weld.Part1 = child
			weld.Parent = child
			child.Anchored = false
			workspace.count.Value += 1
		end
	end
    task.wait()
end

but it makes the script take a long time to run. Is there a way to fix this?

2 Likes

you can try to increase the timeout

Why are you adding 90k welded parts?
Why not Anchor the Parts instead of welding them?
Is this for a destructible Terrain type effect?
You could try having ‘zones’ of parts in different folders, then weld each folder separately to get rid of doing them in one huge chunk.

Your goal is essentially to run a loop as many times per frame as possible, without actually slowing the frame down. I would perform benchmarking on this loop, figure out about how long each iteration takes. Say each iteration takes 1/300th of a second. It is way less, but I will use that for example. Knowing that roblox task scheduler runs 60/s, in order to not yield the scheduler we would need to jump to the next frame of the scheduler using task.wait() every (1/60)/(1/300), or 5 iterations. To implement this:

local singleIterationTime = 1/300
local iterationGroupSize = (1/60)/(singleIterationTime)

for i,child in someHugeArray do
     --task you benchmarked
     if i%iterationGroupSize==0 then task.wait() end --//Allow scheduler to advance to next step, to stop any lag, and more importantly timing out.
end
2 Likes

This is for a destructible buildings effect, I have another script that divides the part and then this script welds them

How do you benchmark to find how long each iteration takes?

Inside of the for loop. you can simply put a task.wait() and yea that takes a while for sure. but to minimize the wait time. in an if statement just take the index of your table and do a modulo operation on it by 5000 or so. (that would look like this _ % 5000) then just check if that value is equal to 1

if it is just run task.wait() and it should be better but I dont know of any better way to do it.

it would look like this in the end

for _, child in pairs(Children) do
	-- Your code here

	if _ % 5000 == 1 then
		task.wait()
	end
end

2 Likes
local singleIterationTime = 1/300
local iterationGroupSize = (1/60)

for i, child in someHugeArray do
  local startTime = tick()  -- Capture start time for this iteration

  -- Your task here

  local endTime = tick()  -- Capture end time for this iteration

  local elapsedTime = endTime - startTime  -- Calculate actual elapsed time

  warn("Elapsed time for iteration "..i..":", elapsedTime)

  --//Allow scheduler to advance to next step, to stop any lag, and more importantly timing out.
  if i % iterationGroupSize == 0 then
    task.wait()
  end 
end

The code utilizes the tick() function within a loop to measure the time elapsed between iterations. The elapsedTime is calculated using the difference endTime - startTime, and then the actual elapsed time for each iteration is displayed along with a warn

1 Like

The lower the number is, the less likely that it will exhaust the execution time right?

I just tried a new script that welds the parts to adjacent parts and now it’s even worse:

local main = workspace.Terrain
for _, child in ipairs(voxelGroup:GetChildren()) do
	if child:IsA("BasePart") then
		if child ~= main then
			local touching = workspace:GetPartBoundsInBox(CFrame.new(child.Position), child.size)
			for part in touching do
				local weld = Instance.new("WeldConstraint", child)
				weld.Part0 = child
				weld.Part1 = touching[part]
			end
			child.Anchored = false
			workspace.count.Value += 1
			--[[
			local weld = Instance.new("WeldConstraint")
			weld.Part0 = main
			weld.Part1 = child
			weld.Parent = child
			workspace.count.Value += 1
			]]--
		end
	end
	if _ % 700 == 1 then
		task.wait()
	end
end

if you have 90k parts then you should really only weld and load them in chunks

so use the camera’s position or player’s position to load in chunks of these parts and weld them together
doing it all at once and always having so many parts is gonna be laggy

Considering welding to all touching parts for evenly spaced cubes would involve 6 times the number of welds you can see why it gets worse.

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