So this is my code
Can someone explain why using while wait() do was laggier than runservice renderstepped?
I want to make a minigame so should i use while wait() do or runservice renderstepped for the loop?
the wait(100) is temporary
So this is my code
Can someone explain why using while wait() do was laggier than runservice renderstepped?
I want to make a minigame so should i use while wait() do or runservice renderstepped for the loop?
the wait(100) is temporary
wait()
will yield the code for a minimum of two frames. On the other hand, task.wait()
, RenderStepped:Wait()
, Heartbeat:Wait()
, and Stepped:Wait()
will all yield for just one frame.
Usually, it’s discouraged to use while [true] do
loops for repetitive tasks, since it can become cumbersome to break out of the loop (the break
statement needs to be inside the loop itself which can be difficult to manage).
Instead of while task.wait()
or while RenderStepped:Wait()
, you should be using the RBXScriptConnections associated with them instead.
so what should i use for my minigame script?
Answer that for yourself, should the loop be faster? Does it need to update every single frame? Does it need to look “smooth” to the player? Will it have performance implications if I make it update twice as fast?
I don’t know anything about your game, but you do.
would you recommend me to use renderstepped or while wait() do
Tachiyen, pretty much answered your question already:
He said:
Instead of while task.wait()
or while RenderStepped:Wait()
, you should be using the RBXScriptConnections associated with them instead.
So you should use events instead of task wait() or renderstepped for what you are trying to do. Find an event like playeradded or characteradded to do what you need. And you should probably avoid things like this:
if (Holder:FindFirstChild..... then
Holder:FindFirstChild(same stuff)
You are doing the search twice on the same object
Instead define a local var and test the var like
local result = Holder:FindFirstChild...
if result ~= nil then result:Destroy()
roblox now has a new task library: Task Library - Now Available!
and it is said here that
so its a good idea to use task.wait()
and task.wait()
is equivalent in behaviour to RunService.Heartbeat:Wait()
What you are doing is known as Polling. Polling is when you are constantly checking for something even if it’s false. This means your wasting processing power
Instead of checking if an instance exists and then destroying it, just use the given RBXScriptSignals that not only are more performant but also garuantees it runs immediately
Here’s a rewrite with event-driven functions
local Holder = script.Parent:WaitForChild("Holder")
local Bar = script:WaitForChild("Bar")
function createBar(Player)
local String = "@"..Player.Name
local newBar = Bar:Clone()
newBar.Name = String
newBar.PlayerName.Text = String
newBar.Visible = true
newBar.Parent = Holder
local Char = Player.Character or Player.CharacterAdded:Wait()
local Root = Char:WaitForChild("HumanoidRootPart")
-- Looping is the only way to get the Position since connecting events to changes in physics doesn't do anything
local Loop = game:GetService("RunService").Heartbeat:Connect(function()
newBar.Position = UDim2.new(0,0,0.9-(Root.Position.Y/100),0)
end)
Player.Destroying:Once(function()
Loop:Disconnect() -- Make sure it gets Disconnected to prevent a memory leak
newBar:Destroy()
end)
Player.CharacterRemoving:Wait()
task.defer(game.Destroy,Char) -- Make sure the Character really does get Destroyed
end
--//
for _,v in game:GetService("Players"):GetPlayers() do
createBar(v)
end
game:GetService("Players").PlayerAdded:Connect(createBar)
game:GetService("Players").PlayerRemoving:Once(function(Player)
task.defer(game.Destroy,Player) -- Make sure the Player really does get Destroyed
end)
For future reference, never use while wait(n)/task.wait(n) do
. That idiom abuses the fact that wait/task.wait
returns a truth-y value and really isn’t performant. If you do need code to run every once and a while just count the DeltaTime
for Heartbeat
local elapseTime = 0
game:GetService("RunService").Heartbeat:Connect(function(dt)
elapseTime += dt
if elapseTime >= 10 then
elapseTime = 0
-- stuff
end
end)
That lib is an improvement over the old equivalents, however, the new versions still have similar drawbacks compared to event handling. The task lib is convenient, but not the ideal or best performant solution. So, they are convenient, but hardly a good idea.
so are you saying that
game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
end)
is more performant then
while true do
local deltaTime = task.wait()
end
because i see no difference in the micro profiler code inside Heartbeat runs at the same speed as code put inside the while loop
I don’t think the while loop is correctly utilized. Also I’m not exactly sure about while task.wait() do
either. You should only use the while loop when a statement is needed to stop it, unless it is intentionally an infinite loop for a specific design of a flow.
No, I’m not saying that at all. I’m saying running a while loop that loops over all the players and searches strings, researches the same string and creates instances and parents parts, possibly unnecessarily, is not as performant as using an event to do the task only when needed. In this case, the performance we are getting from events is spreading the work out over time so there won’t be a giant loop delay and prevents execution when there is no work to be done. I was comparing the while loop processing to event processing.
As to your example, the heartbeat function runs at the frame rate of your game. If you need something to run each frame for certain performance characteristics, this would be a good choice. But, it won’t be a good choice if the task you are doing involves ALL the players, i.e. is not brief or cannot be completed faster than the frame time.
The while loop using the task wait() won’t be a good choice if the platform you are running on is busy and can’t service the loop when the wait time expires especially when you choose a short wait time. This is probably the case that causes lag the most when the expected frequency of this loop fails. If you simulate this scenario in your test example, you will see the heartbeat is smoother.
In short, it depends on what type of performance you are looking for that dictates what pattern you should use to solve your requirements. T
Tachiyen said pretty much the same thing above when he wrote:
Answer that for yourself, should the loop be faster? Does it need to update every single frame? Does it need to look “smooth” to the player? Will it have performance implications if I make it update twice as fast?
When you answer these questions you will know if you should use events, while wait, heartbeat, whatever.
oh I was mistaken when you said event handling I assumed you was talking about runservice events but yes i agree with you that only running code on events that fire sometimes is better then running code every frame but the ops question was Can someone explain why using while wait() do was laggier than runservice renderstepped?
and if you look at the screenshot the op is moving gui based on all the players Y position and i’m not aware of any events to detect when a players position has changed and the position of characters move so often that it will most likely need to be done every frame so events is not really a option for the op
here is a demo project of how you can set GUI based on the players height
PlayerHeightGui.rbxl (40.4 KB)
and this is the code used inside the demo project
local runService = game:GetService("RunService")
local playersService = game:GetService("Players")
local imageLabel = script.Parent.ImageLabel
local players = {}
local height = 100
local function PlayerAdded(player)
local clone = imageLabel:Clone()
clone.Image = playersService:GetUserThumbnailAsync(player.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size60x60)
clone.Parent = script.Parent
players[player] = clone
end
local function PlayerRemoving(player)
players[player]:Destroy()
players[player] = nil
end
local function Heartbeat(deltaTime)
for player, imageLabel in players do
if player.Character == nil then continue end
local y = math.clamp(player.Character:GetPivot().Position.Y / height, 0, 1)
imageLabel.Position = UDim2.new(0.5, 0, 1-y, 0)
end
end
imageLabel.Parent = nil
for i, player in playersService:GetPlayers() do PlayerAdded(player) end
playersService.PlayerAdded:Connect(PlayerAdded)
playersService.PlayerRemoving:Connect(PlayerRemoving)
runService.Heartbeat:Connect(Heartbeat)
replacing runService.Heartbeat
with while true do task.wait() end
would give the same results in this demo project both methods will run every frame