Using too many wait()s simultaneously will cause significant performance dip or in some cases will cause your code to infinitely yield. After testing game.Debris:AddItem(), I realised it’s waiting in intervals similar to wait(), so my concern is, if I use too many game.Debris:AddItem() simultaneously, will that cause some throttling and thus kill my performance?
This was the test I realised:
local lastTime = os.clock()
local p = Instance.new("Part", workspace)
p.AncestryChanged:Connect(function()
print("Destroyed after", os.clock() - lastTime) -- This prints around 0.03
end)
game.Debris:AddItem(p, 0.01)
Should I instead opt to using something like this?
local function Debris(item, period)
task.spawn(function()
task.wait(period)
if item and item.Parent ~= nil then
item:Destroy()
end
end)
end
The function above will never throttle because task.wait() uses heartbeat, and if you have any suggestions to make it better, please share.
-- Credits: @LucasMZReal (https://github.com/LucasMZReal)
local function Destroy(instance, duration)
task.delay(duration or 0.0166666667, game.Destroy, instance);
end
I’m not convinced that it’s worth abandoning Debris Service. I just ran a benchmark in Studio with this code:
local debris = game:GetService("Debris")
task.wait(5)
local folder = Instance.new("Folder")
folder.Parent = workspace
local tasktimes = table.create(100)
for test = 1, 100 do
local start = os.clock()
for i = 1, 1000 do
local part = Instance.new("Part")
part.Position = Vector3.new(math.random(-500,500),math.random(-500,500),math.random(-500,500))
part.Parent = folder
task.delay(1, function() part:Destroy() end)
end
task.wait(2)
local stop = os.clock()
tasktimes[test] = (stop - start)
end
local tasktotal = 0
for i = 1, 100 do
tasktotal += tasktimes[i]
end
local debristimes = table.create(100)
for test = 1, 100 do
local start = os.clock()
for i = 1, 1000 do
local part = Instance.new("Part")
part.Position = Vector3.new(math.random(-500,500),math.random(-500,500),math.random(-500,500))
part.Parent = folder
debris:AddItem(part,1)
end
task.wait(2)
local stop = os.clock()
debristimes[test] = (stop - start)
end
local debristotal = 0
for i = 1, 100 do
debristotal += debristimes[i]
end
print("Duration Average for task.delay: "..(tasktotal/100))
print("Duration Average for debris service: "..(debristotal/100))
And got these results:
So it really seems to me like they take about the same amount of time either way.
While this is a good benchmark, it’s running on your presumably powerful machine with no external load on the environement. The real tests will happen in a server full of players and other variables that come into play, and according to your benchmark, task.delay will help ease up a lot of load on the server thus yielding better experience.
-- debris
game:GetService("Debris"):AddItem(workspace.Baseplate, 25);
script:Destroy();
-- no debris
local function Destroy(instance, duration)
task.delay(duration or 0.0166666667, game.Destroy, instance);
end
Destroy(workspace.Baseplate, 25);
script:Destroy();
I think I remembered the issue wrong. Actually the problem is that if the object is already destroyed (like by another script or by falling to the void) then the code would error.
-- script 1:
local function Destroy(instance, duration)
task.delay(duration or 0.0166666667, game.Destroy, instance);
end
Destroy(workspace.Baseplate, 25);
-- script 2
workspace.Baseplate:Destroy();
And it still worked without any errors.
Debris is actually the culprit here. By the time the service is loaded, Baseplate is already destroyed and thus it errors:
-- script 1
game:GetService("Debris"):AddItem(workspace.Baseplate, 25);
workspace.Baseplate:Destroy(); --> Baseplate is not a valid member of Workspace "Workspace"
-- script 2:
workspace.Baseplate:Destroy();