How to limit execution time of a function call in Python

后端 未结 10 1928
遥遥无期
遥遥无期 2020-11-22 10:25

There is a socket related function call in my code, that function is from another module thus out of my control, the problem is that it blocks for hours occasionally, which

10条回答
  •  无人共我
    2020-11-22 11:20

    I would usually prefer using a contextmanager as suggested by @josh-lee

    But in case someone is interested in having this implemented as a decorator, here's an alternative.

    Here's how it would look like:

    import time
    from timeout import timeout
    
    class Test(object):
        @timeout(2)
        def test_a(self, foo, bar):
            print foo
            time.sleep(1)
            print bar
            return 'A Done'
    
        @timeout(2)
        def test_b(self, foo, bar):
            print foo
            time.sleep(3)
            print bar
            return 'B Done'
    
    t = Test()
    print t.test_a('python', 'rocks')
    print t.test_b('timing', 'out')
    

    And this is the timeout.py module:

    import threading
    
    class TimeoutError(Exception):
        pass
    
    class InterruptableThread(threading.Thread):
        def __init__(self, func, *args, **kwargs):
            threading.Thread.__init__(self)
            self._func = func
            self._args = args
            self._kwargs = kwargs
            self._result = None
    
        def run(self):
            self._result = self._func(*self._args, **self._kwargs)
    
        @property
        def result(self):
            return self._result
    
    
    class timeout(object):
        def __init__(self, sec):
            self._sec = sec
    
        def __call__(self, f):
            def wrapped_f(*args, **kwargs):
                it = InterruptableThread(f, *args, **kwargs)
                it.start()
                it.join(self._sec)
                if not it.is_alive():
                    return it.result
                raise TimeoutError('execution expired')
            return wrapped_f
    

    The output:

    python
    rocks
    A Done
    timing
    Traceback (most recent call last):
      ...
    timeout.TimeoutError: execution expired
    out
    

    Notice that even if the TimeoutError is thrown, the decorated method will continue to run in a different thread. If you would also want this thread to be "stopped" see: Is there any way to kill a Thread in Python?

提交回复
热议问题