Is this a good way of creating a more accurate wait()?

Basically, I wanna avoid using Debris as I’ve heard it can cause so alarming performance concerns, so I created a wait() function using RunService.

function utilities.wait(n)
    n = n or 0.05
    local startTime = os.clock()
    while os.clock() - startTime < n do
        RunService.Heartbeat:Wait()
    end
end

Both “benchmarks” are run 10 times.

Benchmark (Regular wait()):

  Time: 3.0160376999993
  Time: 3.0004384999629
  Time: 3.003573999973
  Time: 3.0133109999588
  Time: 3.0171057999833
  Time: 3.008999099955
  Time: 3.0042302999645
  Time: 3.0039292000001
  Time: 3.0170466999989
  Time: 3.0157013999997

Benchmark (My function) :

  Time: 3.0014120999258
  Time: 3.0026077000657
  Time: 3.0029653999954
  Time: 3.0027549000224
  Time: 3.0033357000211
  Time: 3.0005402999232
  Time: 3.0133224000456
  Time: 3.016337600071
  Time: 3.0172962000361
  Time: 3.0166760999709

Is there a better way to make it even more precise, or is this as far as I can go? As of right now, there really isn’t any difference.

for a wait function i would do:

local function wait(n)
    local elapsed = 0
    local n = n or 0

    repeat
        elapsed = elapsed + RunService.Heartbeat:Wait() -- or renderstepped if you are running on client
    until elapsed >= n
    return elapsed
end

the default wait function is usually really inaccurate when you have lots of lag, otherwise, its fine
your function seems fine too, so ok

This is the benchmark with your code. Slightly modified.

Slighly modified code:

function utilities.wait(n)
    n = n or 0.05
    local elapsedTime = 0

    while elapsedTime <= n do
        elapsedTime += RunService.Heartbeat:Wait()
    end
end

Benchmark @thatNOOBisSMART’s code slightly modified:

  Time: 3.0037713000784
  Time: 2.9867671999382
  Time: 2.9848225000314
  Time: 2.9909544999246
  Time: 3.0033035000088
  Time: 2.9868124999339
  Time: 2.9880444000009
  Time: 2.9980238999706
  Time: 2.9899534999859
  Time: 2.9915780000156

It’s a little bit quicker, which is kinda odd.

Your function custom wait function is nearly as accurate as the default wait() time, so I don’t really think the slim increase in accuracy is worth the expense.

You can do something like this which is very close to perfectly accurate, but be warned that it will definitely self destruct if try to use a large wait time. And again, I don’t really think the accuracy is worth the extra expense.

local function accuWait(seconds)
	local start = tick()
	while tick() - start < seconds do end
end

This is the benchmark I got with this function:

Time: 3.0000004768372
Time: 3 (x3)
Time: 3.0000159740448
Time: 3 (x2)
Time: 3.0000054836273
Time: 3.0000002384186
Time: 3

EDIT:
I decided to add to this because I think I came up with a much better idea for a wait function. It uses the default wait function for the wait time, except for the last 0.5 seconds which will use the while do end loop, drastically decreasing the expense and will fix the issue of breaking with large wait values. Plus, based off of a single test, this function seems a bit more accurate.

local function accuWait(seconds)
	local start = tick()
	if seconds >= 1 then
		wait(seconds - (seconds-.5)) -- leaves 0.5 seconds left
	end
	while tick() - start < seconds do end
	print("Time:" , tick() - start)
end

Benchmark:

Time: 3 (x4)
Time: 3.0000002384186
Time: 3.0000205039978
Time: 3 (x4)
2 Likes

that is because you are doing

while elapsedTime <= n do

you should do

while elapsed >= n do

Nope, the code I used was correct as when I use your suggestion the benchmark is now.

  Time: 1.2998934835196e-06
  Time: 1.3000098988414e-06
  Time: 1.1000083759427e-06
  Time: 1.3000098988414e-06
  Time: 2.4000182747841e-06
  Time: 1.1000083759427e-06
  Time: 1.3000098988414e-06
  Time: 1.1998927220702e-06
  Time: 1.0000076144934e-06
  Time: 2.2000167518854e-06

I used the original, while it’s accurate, it basically blows up.

I use os.clock() since tick() has been hinted at getting deprecated eventually.

function utilities.wait(n)
    n = n or 0.05
    local startTime = os.clock()

    while os.clock() - startTime < n do end
end

Benchmark:

  Time: 3.0000016998965
  Time: 3.000002500019
  Time: 3.0000020998996
  Time: 3.000002100016
  Time: 3.0000022000168

I don’t want to use a stock wait() in my custom wait().

1 Like

Using code provided by, @MayorGnarwhal, I’ve been able to “bypass” the “bomb”, by using Stepped to wait.

function utilities.wait(n)
    n = n or 0.05
    local startTime = os.clock()

    while os.clock() - startTime < n do 
        RunService.Stepped:Wait()
    end
end

Benchmark:

  Time: 3.0006884000031
  Time: 3.000032999902
  Time: 3.0015666999388
  Time: 3.0017324999208
  Time: 3.0014354001032
  Time: 3.0117551999865
  Time: 3.0024064999307
  Time: 3.0022999999346
  Time: 3.0162526998902
  Time: 3.0011164000025

I’m pretty satisfied with the result, but if there are any other solutions I’d be glad to try them out.

4 Likes

I understand this, but I figured it was the easiest way to implement the accuracy of the while do end loop without creating a “bomb”.

Your current Stepped loop is far more accurate, but I think it might do you good to do something like what I did with the stock wait, and use the Stepped/Heartbeat loop for the majority of the wait to prevent the bomb, and then use the while do end for the last half second or so to maintain that accuracy.

1 Like
local t1 = tick()
accuWait(0.1)
local t2 = tick()
print(t2-t1)

Output: 0.10000061988831

Amazing. While I want to like your solution better, it does create a lag spike as you would expect by looping without waiting :frowning: