From: pacopyc on
Hi, I've a question for you. I'd like to call a function and waiting
its return value for a time max (30 sec).
The function could not respond and then I must avoid to wait for
infinite time. OS is Windows XP.
Can you help me?

Thank
From: Albert Hopkins on
On Tue, 2010-05-18 at 02:45 -0700, pacopyc wrote:
> Hi, I've a question for you. I'd like to call a function and waiting
> its return value for a time max (30 sec).
> The function could not respond and then I must avoid to wait for
> infinite time. OS is Windows XP.
> Can you help me?
>
> Thank

This is how I do it with a function decorator. I probably borrowed this
from someone and not attributed it. Anyway, it works on Linux, not sure
about Windows:

def function_timeout(seconds):
"""Function decorator to raise a timeout on a function call"""
import signal
class FunctionTimeOut(Exception):
pass

def decorate(f):
def timeout(signum, frame):
raise FunctionTimeOut()

def funct(*args, **kwargs):
old = signal.signal(signal.SIGALRM, timeout)
signal.alarm(seconds)

try:
result = f(*args, **kwargs)
finally:
signal.signal(signal.SIGALRM, old)
signal.alarm(0)
return result

return funct

return decorate


From: Bryan on
pacopyc wrote:
> I'd like to call a function and waiting
> its return value for a time max (30 sec).
> The function could not respond and then I must avoid to wait for
> infinite time. OS is Windows XP.

You can do that using the multiprocessing module, which is in the
standard library of Python 2.6 or better. It has certain limitations,
but works on XP.

The functions have to be defined at module scope, and the arguments
and return value must be pickleable. The way multiprocessing works on
Windows, it launches a new process which runs the Python interpreter
on the module again, and pickles the arguments to pipe them to the new
process.

Below is a simple working demo/test. The demo uses a timeout of 1
second, rather than the specified 30, to avoid excessive boringness.
In practice, timeout_function() would be recklessly inefficient for
controlling quick operations; it creates a new pool of processes for
each function call that it might need to time-out. That's fixable, but
the question here is about a 30-second-plus processing problem, and in
that kind of case the overhead of creating one or a few new processes
is lost in the noise.

-Bryan Olson

#--------------------

from multiprocessing import Pool, TimeoutError

def timeout_function(timeout, f, args=(), kwargs={}):
""" Return f(*args, **kwargs), or if that takes
to long raise multiprocessing.TimeoutError.
"""
pool = Pool(1)
return pool.apply_async(f, args, kwargs).get(timeout)


#--------------
# simple demo-test:

from random import random as rand
from time import sleep

def sillyfunc(sleeptime):
# Time-absorbing function for testing
sleep(sleeptime)
return 'Done.'

if __name__ == '__main__':
timeout = 1.0
print "Timeout is %f seconds" % timeout
trials = 100
ntimeouts = 0
for _ in range(trials):

# time-out probability a bit over 0.5
sleeptime = rand() * timeout * 2

try:
result = timeout_function(
timeout,
sillyfunc,
(sleeptime,))
assert result == 'Done.'
print 'Ran without timing out'

except TimeoutError:
ntimeouts += 1
print 'Timed out'
if sleeptime < timeout:
print '...Sucks! Slept %f' % sleeptime

print 'Timed out %d out of %d' % (ntimeouts, trials)

From: Terry Reedy on
On 5/18/2010 6:24 AM, Albert Hopkins wrote:
> On Tue, 2010-05-18 at 02:45 -0700, pacopyc wrote:
>> Hi, I've a question for you. I'd like to call a function and waiting
>> its return value for a time max (30 sec).
>> The function could not respond and then I must avoid to wait for
>> infinite time. OS is Windows XP.
>> Can you help me?
>>
>> Thank
>
> This is how I do it with a function decorator. I probably borrowed this
> from someone and not attributed it. Anyway, it works on Linux, not sure
> about Windows:
>
> def function_timeout(seconds):
> """Function decorator to raise a timeout on a function call"""
> import signal
> class FunctionTimeOut(Exception):
> pass
>
> def decorate(f):
> def timeout(signum, frame):
> raise FunctionTimeOut()
>
> def funct(*args, **kwargs):
> old = signal.signal(signal.SIGALRM, timeout)
> signal.alarm(seconds)

from help(signal):
alarm() -- cause SIGALRM after a specified time [Unix only]

I do not know of any replacement in the stdlib, but one could check the
code for multiprocessing to see how it does a timeout. Or check the
pywin32 library
http://pypi.python.org/pypi/pywin32/210

> try:
> result = f(*args, **kwargs)
> finally:
> signal.signal(signal.SIGALRM, old)
> signal.alarm(0)
> return result
>
> return funct
>
> return decorate
>
>