我正在使用Twisted在回调中的for循环中重复一个任务,但是如果用户通过Ctrl-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()
答案 0 :(得分: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()
答案 1 :(得分:6)
这是为了避免(半)抢占,因为Twisted是一个合作的多任务系统。 Ctrl-C在Python中处理,启动时由解释器安装SIGINT处理程序。处理程序在调用时设置标志。执行每个字节代码后,解释器检查该标志。如果已设置,则在此时引发KeyboardInterrupt。
reactor安装自己的SIGINT处理程序。这取代了解释器处理程序的行为。反应堆的处理程序启动反应堆关闭。由于它不会引发异常,因此不会中断正在运行的代码。循环(或其他)完成,当控制返回到反应堆时,停止继续。
如果你宁愿让Ctrl-C(即SIGINT)引发KeyboardInterrupt,那么你可以使用信号模块恢复Python的SIGINT处理程序:
signal.signal(signal.SIGINT, signal.default_int_handler)
但是,请注意,如果在Twisted的代码运行时发送SIGINT而不是您自己的应用程序代码,则行为未定义,因为Twisted不会被KeyboardInterrupt中断。