RE: how to run an arbitrary function with timeout?

Discussion in 'Python' started by Tim Peters, May 14, 2004.

  1. Tim Peters

    Tim Peters Guest

    [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.
    Tim Peters, May 14, 2004
    #1
    1. Advertising

  2. "Tim Peters" <> wrote:

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


    ok, let me rephrase my question.

    i would like a function RunWithTimeout( func, args, timeout )
    i would like it to invoke the function func on arguments args.
    if timeout seconds elapse before func(args) returns, i would
    like it to raise an exception. if func(args) returns before timeout
    seconds, i would like it return the result.

    can anyone help?

    thanks

    ----
    Garry Hodgson, Technology Consultant, AT&T Labs

    Be happy for this moment.
    This moment is your life.
    Garry Hodgson, May 14, 2004
    #2
    1. Advertising

  3. Tim Peters

    Mark Day Guest

    In article <>, Garry Hodgson
    <> wrote:

    > i would like a function RunWithTimeout( func, args, timeout )
    > i would like it to invoke the function func on arguments args.
    > if timeout seconds elapse before func(args) returns, i would
    > like it to raise an exception. if func(args) returns before timeout
    > seconds, i would like it return the result.


    I'm guessing you want the exception raised after func has executed for
    timeout seconds (as opposed to waiting for func to complete).

    Since you can't stop func from the outside (as Tim said), I suppose you
    could run func in a separate thread. From the original thread, you'd
    have to wait for either timeout seconds or until func completes,
    whichever comes first. If the timeout happened first, then raise the
    exception (else you presumably return func's result). I'm no expert on
    threading in Python, but I'll bet the Library Reference has the
    information you need.

    -Mark
    Mark Day, May 15, 2004
    #3
  4. Mark Day <> writes:
    > In article <>, Garry Hodgson
    > <> wrote:
    >
    >> i would like a function RunWithTimeout( func, args, timeout )
    >> i would like it to invoke the function func on arguments args.
    >> if timeout seconds elapse before func(args) returns, i would
    >> like it to raise an exception. if func(args) returns before timeout
    >> seconds, i would like it return the result.

    >
    > I'm guessing you want the exception raised after func has executed for
    > timeout seconds (as opposed to waiting for func to complete).
    >
    > Since you can't stop func from the outside (as Tim said), I suppose you
    > could run func in a separate thread. From the original thread, you'd
    > have to wait for either timeout seconds or until func completes,
    > whichever comes first. If the timeout happened first, then raise the
    > exception (else you presumably return func's result). I'm no expert on
    > threading in Python, but I'll bet the Library Reference has the
    > information you need.


    just use alarm and use a signal handler to be called after N seconds,
    this is how I do it: (I've omitted the definition of the exception for
    brevity)

    -----------------------------------------------------------

    import signal

    #
    # a alarm signal handler
    #
    def alarmHandler(signum, frame):
    raise TimeExceededError, "Your command ran too long"

    #
    # a function that would run for too long
    #
    def infinite():
    while 1:
    pass
    return

    #
    # set the alarm signal handler, and set the alarm to 1 second
    #
    signal.signal(signal.SIGALRM, alarmHandler)
    signal.alarm(1)

    #
    # the function infinite would never return, after 1 second the signalHandler
    # is called, which immediately just raises the exception.
    #
    try:
    infinite()
    except TimeExceededError:
    # but after 1 second, the alarmHandler raises this
    # exception
    print "code must have gone crazy..."

    -----------------------------------------------------------
    Joseph T. Bore, May 17, 2004
    #4
  5. Tim Peters

    Tony C Guest

    (Joseph T. Bore) wrote in message news:<>...
    > Mark Day <> writes:
    > > In article <>, Garry Hodgson
    > > <> wrote:

    > import signal
    >
    > #
    > # a alarm signal handler
    > #
    > def alarmHandler(signum, frame):
    > raise TimeExceededError, "Your command ran too long"
    >
    > #
    > # a function that would run for too long
    > #
    > def infinite():
    > while 1:
    > pass
    > return
    >
    > #
    > # set the alarm signal handler, and set the alarm to 1 second
    > #
    > signal.signal(signal.SIGALRM, alarmHandler)
    > signal.alarm(1)


    This is a very interesting solution.
    However, signal.alarm() and signal.SIGALRM are not defined in my signal module
    I'm using 2.3.3
    Tony C, May 18, 2004
    #5
  6. (Tony C) writes:
    >> # set the alarm signal handler, and set the alarm to 1 second
    >> #
    >> signal.signal(signal.SIGALRM, alarmHandler)
    >> signal.alarm(1)

    >
    > This is a very interesting solution.
    > However, signal.alarm() and signal.SIGALRM are not defined in my signal module
    > I'm using 2.3.3


    I'm using 2.2.1, but it's on unix/linux. It looks like the alarm
    functionality is only available there. I guess there must be
    something similar on windows, anyone have any ideas?

    jb
    Joseph T. Bore, May 18, 2004
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Honestmath
    Replies:
    5
    Views:
    554
    Honestmath
    Dec 13, 2004
  2. Garry Hodgson
    Replies:
    0
    Views:
    284
    Garry Hodgson
    May 14, 2004
  3. mshiltonj
    Replies:
    2
    Views:
    251
    mshiltonj
    Jul 8, 2007
  4. Mark Probert

    Timeout::timeout and Socket timeout

    Mark Probert, Oct 6, 2004, in forum: Ruby
    Replies:
    1
    Views:
    1,279
    Brian Candler
    Oct 6, 2004
  5. Îίκος
    Replies:
    17
    Views:
    190
    Dennis Lee Bieber
    Oct 3, 2013
Loading...

Share This Page