A better way to timeout a class method?

John O'Hagan research at johnohagan.com
Tue Mar 10 02:37:21 EDT 2009


On Mon, 9 Mar 2009, Nick Craig-Wood wrote:
> John O'Hagan <research at johnohagan.com> wrote:
> >  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.
>
> 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



More information about the Python-list mailing list