call_ignore_timeout (and call_retry_until)
SKILL LEVEL: Beginner
This lets you run code that would otherwise exceed the instruction limit. It can be used in any situation where you want a loop to complete regardless of the instruction limit. Procedural content generation is my use case.
I made this because I'm doing some procedural level generation that runs fairly slowly, and I want to be able to run a loop as fast as possible. That means I can't add a Task.Wait()
call every iteration (or every 100 iterations or whatever) for two reasons: it still has a chance of failing because not every iteration takes the same amount of time, and it forces me to run it way slower than the theoretical limit because I need to prevent it from failing.
Here's the code (2 functions)
function call_retry_until(retry_callback, until_callback)
local success, result
repeat
success, result = pcall(retry_callback)
if success then
return true, result
else
local err = result
if until_callback(err) then
Task.Wait()
else
return false, err
end
end
until success
return true, result
end
function call_ignore_timeout(callback)
local timeout_err_suffix = "Instruction limit exceeded. Your code may be in an infinite loop."
local success, result
return call_retry_until(callback, function(err)
return err and err:find(timeout_err_suffix, -timeout_err_suffix:len())
end)
end
It's not much use to keep calling a function again and again if it just keeps failing in the same way, so you should use it to call a function that makes some progress every time it's called.
Here's a simplified usage example
local progress = 0
local function try_generating()
generate_block(progress)
progress = progress + 1
end
local success, result = call_ignore_timeout(try_generating)
If you know for sure that the only way that your function can error is by exceeding the instruction limit, you can replace return err and err:find(timeout_err_suffix, -timeout_err_suffix:len())
with return true
to omit the check. This might make it a bit faster.
You can also use call_retry_until
to repeatedly try calling a function when it gives you any error or any other condition is met, not just the instruction limit exceeded error.
1 Like
Hi, thanks for this.
Is this "instruction limit" documented somewhere? Like how much CPU time an script can take for its own use on a single call. How many calls or iterations?
Similar use cases: Procedural generation and level data pre-processing.
1 Like
I tried your functions but still get the exception error.
This is my code, was not easy for me to understand what you did, I never use pcall :-o . Please let me know what I did wrong.
My code is just a benchmark test to try your functions:
local function write(s)
UI.PrintToScreen(s)
end
local function sysInfo()
write(_VERSION)
end
function call_retry_until(retry_callback, until_callback)
local success, result
repeat
success, result = pcall(retry_callback)
if success then
return true, result
else
local err = result
if until_callback(err) then
Task.Wait()
else
return false, err
end
end
until success
return true, result
end
function call_ignore_timeout(callback)
local timeout_err_suffix = "Instruction limit exceeded. Your code may be in an infinite loop."
local success, result
return call_retry_until(callback, function(err)
return err and err:find(timeout_err_suffix, -timeout_err_suffix:len())
end)
end
local progress = 0
local total = 0
local numIters = 0
local function benchRandomMath()
while progress < numIters do
total = total + 10 * math.sin( math.random() * 3.14 )
total = total + math.sqrt(progress) * math.cos(progress)
progress = progress + 1
end
end
local function runAll()
sysInfo()
progress = 0
numIters = 100100
local tstart = time()
--benchRandomMath()
local success, result = call_ignore_timeout(benchRandomMath)
print(sucess, result)
local duration = getTime() - tstart
write('Random Math: '..tostring(duration)..' seconds. Result ='..tostring(total))
end
runAll()
1 Like
I'm afraid an update a while ago made this workaround impossible, I haven't been on the Core platform since because the change basically meant my WIP proc-gen based game had no chance of working fast enough So I don't know if any new workarounds have been found since.
I think your best chance is making a feedback/feature request in the community Discord server asking for an official way of "running code as fast as possible" or for the change that broke the workaround to be revoked.
1 Like
That's sad to hear.
That's one heavy point against the balance between the Nice features VS justified limitations.
I barely understand discord, I'm old guy I thought a forum was the most "official".
Thanks for your answer.
1 Like
I think the Discord server is just as official, and since these forums aren't used very much I think you'll have more luck if you post on the Discord instead, for example in the core-feedback or lua-help channels. Someone there might know a different workaround, or you might even get the attention of Core staff if you post in the feedback channel.
1 Like