Timeout Function If It Takes Too Long to Finish

Timeout function if it takes too long to finish

The process for timing out an operations is described in the documentation for signal.

The basic idea is to use signal handlers to set an alarm for some time interval and raise an exception once that timer expires.

Note that this will only work on UNIX.

Here's an implementation that creates a decorator (save the following code as timeout.py).

import errno
import os
import signal
import functools

class TimeoutError(Exception):
pass

def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
def decorator(func):
def _handle_timeout(signum, frame):
raise TimeoutError(error_message)

@functools.wraps(func)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result

return wrapper

return decorator

This creates a decorator called @timeout that can be applied to any long running functions.

So, in your application code, you can use the decorator like so:

from timeout import timeout

# Timeout a long running function with the default expiry of 10 seconds.
@timeout
def long_running_function1():
...

# Timeout after 5 seconds
@timeout(5)
def long_running_function2():
...

# Timeout after 30 seconds, with the error "Connection timed out"
@timeout(30, os.strerror(errno.ETIMEDOUT))
def long_running_function3():
...

Timeout on a function call

You may use the signal package if you are running on UNIX:

In [1]: import signal

# Register an handler for the timeout
In [2]: def handler(signum, frame):
...: print("Forever is over!")
...: raise Exception("end of time")
...:

# This function *may* run for an indetermined time...
In [3]: def loop_forever():
...: import time
...: while 1:
...: print("sec")
...: time.sleep(1)
...:
...:

# Register the signal function handler
In [4]: signal.signal(signal.SIGALRM, handler)
Out[4]: 0

# Define a timeout for your function
In [5]: signal.alarm(10)
Out[5]: 0

In [6]: try:
...: loop_forever()
...: except Exception, exc:
...: print(exc)
....:
sec
sec
sec
sec
sec
sec
sec
sec
Forever is over!
end of time

# Cancel the timer if the function returned before timeout
# (ok, mine won't but yours maybe will :)
In [7]: signal.alarm(0)
Out[7]: 0

10 seconds after the call signal.alarm(10), the handler is called. This raises an exception that you can intercept from the regular Python code.

This module doesn't play well with threads (but then, who does?)

Note that since we raise an exception when timeout happens, it may end up caught and ignored inside the function, for example of one such function:

def loop_forever():
while 1:
print('sec')
try:
time.sleep(10)
except:
continue

Skip the function if executing time too long. JavaScript

setTimeout cannot be used to halt the execution of a function

setTimeout cannot be used to cancel the execution of a function. setTimeout is simply a delay before your function is called. Which simply means, yes you can stop it before it's executed but once it's executed you can't.

Halt by checking the time lapsed (not recommended).

A solution would be to check how much time the function is taking by placing checks a bit everywhere in your function.

function A(mili){  const end = Date.now() + mili;  for(let i = 0; i < 10000; i++){    for(let j = 0; j < 10000; j++){      if(Date.now() > end){        console.log(mili + ": Halting A...");        return;      }    }  }  }
A(100); //haltedA(1000); //haltedA(10000); //passed

timeout if method takes too long to finish

What I ended up doing:

    class Timeout
{
XmlDocument doc;
System.Object input;

public Timeout(XmlDocument doc, System.Object input)
{
this.doc = doc;
this.input = input;
}

public void run()
{
if (input is Stream)
{
doc.Load((Stream)input);
}
else if (input is XmlReader)
{
doc.Load((XmlReader)input);
}
else if (input is TextReader)
{
doc.Load((TextReader)input);
}
else
{
doc.Load((string)input);
}
}
}

private void LoadXmlDoc(XmlDocument doc, System.Object input)
{
Timeout timeout = new Timeout(doc, input);
System.Threading.Thread timeoutThread = new System.Threading.Thread(new ThreadStart(timeout.run));
timeoutThread.Name = "XmlWorker" + threadNumber++;
timeoutThread.Start();
if (!timeoutThread.Join(this.timeout)) //Join returning false implies the timeout was reached
{
if (timeoutThread.IsAlive)
timeoutThread.Abort();
throw new DataConnectionException("timeout reached: " + this.timeout.Milliseconds + "ms", new TimeoutException(this.timeout.Milliseconds));
}
}

Break the function after certain time

I think creating a new process may be overkill. If you're on Mac or a Unix-based system, you should be able to use signal.SIGALRM to forcibly time out functions that take too long. This will work on functions that are idling for network or other issues that you absolutely can't handle by modifying your function. I have an example of using it in this answer:

Option for SSH to timeout after a short time? ClientAlive & ConnectTimeout don't seem to do what I need them to do

Editing my answer in here, though I'm not sure I'm supposed to do that:

import signal

class TimeoutException(Exception): # Custom exception class
pass

def timeout_handler(signum, frame): # Custom signal handler
raise TimeoutException

# Change the behavior of SIGALRM
signal.signal(signal.SIGALRM, timeout_handler)

for i in range(3):
# Start the timer. Once 5 seconds are over, a SIGALRM signal is sent.
signal.alarm(5)
# This try/except loop ensures that
# you'll catch TimeoutException when it's sent.
try:
A(i) # Whatever your function that might hang
except TimeoutException:
continue # continue the for loop if function A takes more than 5 second
else:
# Reset the alarm
signal.alarm(0)

This basically sets a timer for 5 seconds, then tries to execute your code. If it fails to complete before time runs out, a SIGALRM is sent, which we catch and turn into a TimeoutException. That forces you to the except block, where your program can continue.

right way to run some code with timeout in Python

A completely general solution to this really, honestly does not exist. You have to use the right solution for a given domain.

  • If you want timeouts for code you fully control, you have to write it to cooperate. Such code has to be able to break up into little chunks in some way, as in an event-driven system. You can also do this by threading if you can ensure nothing will hold a lock too long, but handling locks right is actually pretty hard.

  • If you want timeouts because you're afraid code is out of control (for example, if you're afraid the user will ask your calculator to compute 9**(9**9)), you need to run it in another process. This is the only easy way to sufficiently isolate it. Running it in your event system or even a different thread will not be enough. It is also possible to break things up into little chunks similar to the other solution, but requires very careful handling and usually isn't worth it; in any event, that doesn't allow you to do the same exact thing as just running the Python code.



Related Topics



Leave a reply



Submit