how to run an arbitrary function with timeout?

Tim Peters tim.one at comcast.net
Fri May 14 12:51:07 EDT 2004


[Garry Hodgson]
> i'm building a test suite on top of unittest, and some
> of the tests involve things that might hang, like trying
> to connect to a wedged server.  so i'd like a simple function
> that i can call that will run a given (func,args) pair and
> return either the value or raise an exception if it times
> out.  this seems like it should be straightforward, but i've
> not had much luck getting it to work.
>
> my latest attempt, below, raises the exception ok,
> but still doesn't return until snooze() completes:

What doesn't return?  The snooze() function?  You told that to sleep for 10
seconds, and it does, then it prints 'waking up' and returns.  Your call to
RunWithTimeout also returns, at the point it raises its exception.  You
can't expect to see "ok" get printed, because when you raise TookTooLong,
RunWithTimeout's invocation ends immediately (as raising an uncaught
exception does in any function, threads or not) -- RunWithTimeout never
executes its "return 'ok'" line.

>    --> xx
>    going to sleep
>    Traceback (most recent call last):
>      File "./xx", line 26, in ?
>        print RunWithTimeout( snooze, (10,), 2 )
>      File "./xx", line 16, in RunWithTimeout
>        raise TookTooLong, 'fsdfsdf'
>    __main__.TookTooLong: fsdfsdf
>
> ...8 second delay here...
>
>    waking up
>
>
> can someone tell me what i'm doing wrong?

Best I can guess, you're expecting something that can't happen, but I'm not
sure exactly what.

> #!/usr/bin/env python2.3
>
> from threading import *
> from time import sleep
>
> class TookTooLong( Exception ):
>         pass
>
> def RunWithTimeout( func, args, timeout ):
>         t = Thread( target=func, args=args )
>         t.start()
>         t.join( timeout )
>
>         if t.isAlive():
>                 del t

That line didn't accomplish anything useful.  If you expected it to "do
something", then that's the problem.  All it does is unbind the local name
"t".  If, for example, you expected it to kill the thread, that won't
happen.

>                 raise TookTooLong, 'fsdfsdf'
>         return 'ok'
>
>
> def snooze( duration ):
>         print 'going to sleep'
>         sleep( duration )
>         print 'waking up'

That function executes in its entirety when you call it, and there's nothing
you can do to stop that (Python doesn't supply any way to stop a thread T
from outside T).

>
> if __name__ == '__main__':
>         print RunWithTimeout( snooze, (10,), 2 )

It would have helped a lot if you had spelled out the output you *expected*
to see.  The output this actually produced is what I expected to see.





More information about the Python-list mailing list