2010-11-08 40 views
3

目前,我正在重复一个任务中使用双绞线回调内部循环中断的回调,但想反应堆打破循环回调(一个),如果用户通过按Ctrl - 发出一个KeyboardInterrupt C。从我测试过的,反应堆只在回调结束时停止或处理中断。扭曲 - 通过一个KeyboardInterrupt

是否有发送一个KeyboardInterrupt回调或回调运行中间的错误处理程序的方法吗?

干杯,

克里斯

#!/usr/bin/env python 

from twisted.internet import reactor, defer 


def one(result): 
    print "Start one()" 
    for i in xrange(10000): 
     print i 
    print "End one()" 
    reactor.stop() 


def oneErrorHandler(failure): 
    print failure 
    print "INTERRUPTING one()" 
    reactor.stop()  


if __name__ == '__main__': 

    d = defer.Deferred() 
    d.addCallback(one) 
    d.addErrback(oneErrorHandler) 
    reactor.callLater(1, d.callback, 'result') 

    print "STARTING REACTOR..." 
    try: 
     reactor.run() 
    except KeyboardInterrupt: 
     print "Interrupted by keyboard. Exiting." 
     reactor.stop() 

回答

6

这是有意避免的(半)抢占,因为扭曲是合作多任务系统。 Ctrl-C在Python中由解释器在启动时安装的SIGINT处理程序处理。处理程序在被调用时设置一个标志。每个字节代码执行后,解释器检查标志。如果它被设置,KeyboardInterrupt在那个时候被引发。

反应器安装自己的SIGINT处理程序。这取代了解释者处理程序的行为。反应堆的处理机启动反应堆停堆。由于它不会引发异常,因此它不会中断正在运行的任何代码。循环(或其他)完成,并且当控制返回到反应堆时,关机继续。

signal.signal(signal.SIGINT, signal.default_int_handler) 

但是请注意,如果你发送一个SIGINT:

如果你宁愿按Ctrl-C(即SIGINT)提高一个KeyboardInterrupt,那么你可以使用信号模块恢复Python的SIGINT处理程序而从扭曲的代码运行,而不是你自己的应用程序代码,该行为是不确定的,因为扭曲不希望由一个KeyboardInterrupt中断。

+0

保罗:非常感谢的说明!我问自己,为什么一半的时候,如果我有一个信号中断,代码从我的代码断绝了成功,但在反应器循环等待时产生异常。 – user500869 2010-11-10 08:46:25

8

我得到这个工作的花花公子。烧制SIGINT设置一个标志运行在我的代码的任何正在运行的任务,并且还要求reactor.callFromThread(reactor.stop)停止任何扭曲运行代码:

#!/usr/bin/env python 

import sys 
import twisted 
import re 
from twisted.internet import reactor, defer, task 
import signal 


def one(result, token): 
    print "Start one()" 
    for i in xrange(1000): 
     print i 
     if token.running is False: 
      raise KeyboardInterrupt() 
      #reactor.callFromThread(reactor.stop) # this doesn't work 
    print "End one()" 

def oneErrorHandler(failure): 
    print "INTERRUPTING one(): Unkown Exception" 
    import traceback 
    print traceback.format_exc() 
    reactor.stop() 

def oneKeyboardInterruptHandler(failure): 
    failure.trap(KeyboardInterrupt) 
    print "INTERRUPTING one(): KeyboardInterrupt" 
    reactor.stop() 

def repeatingTask(token): 
    d = defer.Deferred() 
    d.addCallback(one, token) 
    d.addErrback(oneKeyboardInterruptHandler) 
    d.addErrback(oneErrorHandler) 
    d.callback('result') 

class Token(object): 
    def __init__(self): 
     self.running = True 

def sayBye(): 
    print "bye bye." 


if __name__ == '__main__': 

    token = Token() 

    def customHandler(signum, stackframe): 
     print "Got signal: %s" % signum 
     token.running = False    # to stop my code 
     reactor.callFromThread(reactor.stop) # to stop twisted code when in the reactor loop 
    signal.signal(signal.SIGINT, customHandler) 

    t2 = task.LoopingCall(reactor.callLater, 0, repeatingTask, token) 
    t2.start(5) 

    reactor.addSystemEventTrigger('during', 'shutdown', sayBye) 

    print "STARTING REACTOR..." 
    reactor.run()