中断和取消正在进行的函数调用的最佳(pythonic)方式?

时间:2014-10-02 22:10:11

标签: python multithreading

我希望函数foo()在一个线程中执行许多操作,并在等待期间定期检查另一个线程(主脚本)是否已将please_stop变量设置为{{ 1}},在这种情况下,我希望True立即返回一个值(例如foo())。

我最初的尝试看起来像这样:

False

它可以正常工作,但我发现import time please_stop = False def wait( n ) : ''' Wait n seconds and return True, unless some other process sets please_stop to True (and then return False). ''' global please_stop for t in range (n) : if please_stop : please_stop = False return False else : print t time.sleep(1) return True def foo() : ''' Do a number of things, with wait() calls in between. ''' global please_stop print 'doing first thing' if not wait( 5 ) : return False print 'doing second thing' if not wait( 5 ) : return False print 'doing third thing' return True foo() 表达式非常笨重。实现此行为的最简单/最优雅的方法是什么,可能允许使用简单的if not wait( 5 ) : return False表达式?我是否正在重新发明轮子,中断会不会在这里做得更好?

提前致谢。

1 个答案:

答案 0 :(得分:0)

嗯,您可以使用threading.Event而不是全局变量来简化wait的实现:

import time
import threading


def wait(event, timeout):
    if event.wait(timeout):
        event.clear()
        return False
    else:
        return True

def foo(event):
    '''
    Do a number of things, with wait() calls in between.
    '''
    print 'doing first thing'
    if not wait(event, 5): return False
    print 'doing second thing'
    if not wait(event, 5): return False
    print 'doing third thing'
    return True

if __name__ == "__main__":
    event = threading.Event()
    t = threading.Thread(target=foo, args=(event,))
    t.start()
    time.sleep(6)
    event.set()

输出:

doing first thing
doing second thing

但您仍在使用if not wait(5) : return False模式。要摆脱这种情况,您需要在设置Event时抛出异常。您可能不希望异常逃离foo,因此您需要在try正文周围使用except / foo块,或者使用context manager

import time
import threading
from contextlib import contextmanager

class Interrupt(Exception): pass

def wait(event, timeout):
    if event.wait(timeout):
        event.clear()
        raise Interrupt()
    else:
        return True

@contextmanager
def interruptible():
    try:
        yield
    except Interrupt:
        pass

def foo(event):
    '''
    Do a number of things, with wait() calls in between.
    '''
    with interruptible():
        print 'doing first thing'
        wait(event, 5)
        print 'doing second thing'
        wait(event, 5)
        print 'doing third thing'
        return True
    return False  # This will only be reached the main thread interrupts foo

这与上一个示例的行为完全相同,唯一的区别是不是将False返回到foo,我们引发一个异常,它被上下文管理器捕获,但会导致我们跳过上下文中的其余代码。