A better way to timeout a class method?

J

John O'Hagan

Is there a concise Pythonic way to write a method with a timeout?

I did this:

class Eg(object):

def get_value(self, timeout):

from threading import Timer
self.flag = True

def flag_off():
self.flag = False
timer = Timer(timeout, flag_off)
timer.start()

while self.flag:
#do stuff for a long time to get some value
if condition: #if we ever get the value
self.value = value
break

but it seems hackish to have a special "flag" attribute just to manage the
timeout within the the method.

Any comments appreciated.

Regards,
John

P.S. A more detailed but non-essential example:

The use case is an iterator class which has a method to get the length of an
instance, and does this as a thread so that other operations can proceed. It
is subject to a timeout as the iterator may be arbitrarily long.

Showing just the relevant method:

class ExIt(object):

def __init__(self, iter_func, args=None):
self.iter_func = iter_func
self.args = args
self.length = None

def get_length(self, timeout=None):
"""Try to get length of iterator
within a time limit"""
if self.length is None:

self.flag = True
from threading import Thread
def count():
gen = self.iter_func(self.args)
length = 0
while self.flag:
try:
gen.next()
length += 1
except StopIteration:
self.length = length
break
getlen = Thread(target=count)
getlen.setDaemon(True)

if timeout:
from threading import Timer
def flag_off():
self.flag = False
timer = Timer(timeout, flag_off)
timer.start()

getlen.start()

Any comments on this also appreciated.
 
J

John O'Hagan

No need for threading. Just define a signal handler and call
signal.alarm().
Thanks, that works well in general; but unfortunately the method in question
(see the P.S. in my original post) starts a thread, and it's the thread that
needs to timeout; unfortunately signal doesn't work in a thread. So I guess I
need to rephrase my question as: how to timeout a thread?

Regards,

John
 
J

John O'Hagan

How about something like this

from threading import Timer

class Duration(object):
def __init__(self, duration):
self.running = True
self.timer = Timer(duration, self.set_finished)
self.timer.setDaemon(True)
self.timer.start()
def set_finished(self):
self.running = False
def __nonzero__(self):
return self.running

Nifty! Works for threads too because they can have access to the Duration
object. I guess it works on a similar principle to my attempt (setting a flag
with a timer) but is cleaner by keeping everything inside the method.

So my original method would look like this:

class ExIt(object):
   
    def __init__(self, iter_func, args=None):
        self.iter_func = iter_func
        self.args = args
        self.length = None

    def get_length(self, timeout=None):
        """Try to get length of iterator
        within a time limit"""
        if self.length is None:           
            from threading  import Thread, Timer
timer=Duration(timeout)
            def count():
                gen = self.iter_func(self.args)
                length = 0
                while timer:
                    try:
                        gen.next()
                        length += 1
                    except StopIteration:
                        self.length = length
                        break
            getlen = Thread(target=count)
            getlen.setDaemon(True)                      
            getlen.start()

Which does exactly what I want: runs a time-consuming task in the background
and can optionally time it out. In fact that's so handy, I think it would be
nice if there was a standard timer object which is True while running, then
False. Or maybe there is?

Thanks,

John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top