5

Possible Duplicate:
Timeout on a Python function call
How to timeout function in python, timout less than a second

I am running a function within a for loop, such as the following:

for element in my_list:
    my_function(element)

for some reason, some elements may lead the function into very long processing time (maybe even some infinite loop that I cannot really trace where it comes from). So I want to add some loop control to skip the current element if its processing for example takes more than 2 seconds. How can this be done?

Community
  • 1
  • 1
hmghaly
  • 1,411
  • 3
  • 29
  • 47

2 Answers2

2

I would discourage the most obvious answer - using a signal.alarm() and an alarm signal handler that asynchronously raises an exception to jump out of task execution. In theory it should work great, but in practice the cPython interpreter code doesn't guarantee that the handler is executed within the time frame that you want. Signal handling can be delayed by x number of bytecode instructions, so the exception could still be raised after you explicitly cancel the alarm (outside the context of the try block).

A problem we ran into regularly was that the alarm handler's exception would get raised after the timeoutable code completed.

Since there isn't much available by way of thread control, I have relied on process control for handling tasks that must be subjected to a timeout. Basically, the gist is to hand off the task to a child process and kill the child process if the task takes too long. multiprocessing.pool isn't quite that sophisticated - so I have a home-rolled pool for that level of control.

Jeremy Brown
  • 17,880
  • 4
  • 35
  • 28
1

Something like this:

import signal
import time

class Timeout(Exception): 
    pass 

def try_one(func,t):
    def timeout_handler(signum, frame):
        raise Timeout()

    old_handler = signal.signal(signal.SIGALRM, timeout_handler) 
    signal.alarm(t) # triger alarm in 3 seconds

    try: 
        t1=time.clock()
        func()
        t2=time.clock()

    except Timeout:
        print('{} timed out after {} seconds'.format(func.__name__,t))
        return None
    finally:
        signal.signal(signal.SIGALRM, old_handler) 

    signal.alarm(0)
    return t2-t1

def troublesome():
    while True:
        pass

try_one(troublesome,2)

The function troublsome will never return on its own. If you use try_one(troublesome,2) it successfully times out after 2 seconds.

the wolf
  • 34,510
  • 13
  • 53
  • 71