我将参考这个解释和解决方法:
所以我要做的是:
def interrupted(signum, stackframe): log.warning('interrupted > Got signal: %s', signum) menu.quitMenu = True # to stop my code signal.signal(signal.SIGINT, interrupted) # Handle KeyboardInterrupt
问题是,虽然菜单被通知它必须停止,并且很快就会这样做,但它现在无法做到,因为它被困在raw_input
:
def askUser(self): current_date = datetime.now().isoformat(' ') choice = raw_input('%s > ' % current_date) return choice
因此,由于twisted正在删除默认的中断处理程序,raw_input
因此不会停止.我仍然需要按enter
后^C
它停止.
如何强制raw_input停止,而不安装默认的中断处理程序,这是扭曲上下文中的问题来源(因为扭曲本身不会被期望中断)
我猜这个问题与之无关raw_input
:任何采取无限时间(或超过预设限制)的函数都应该以某种方式中断.
这有可接受的扭曲模式吗?
这是完整的测试代码:
from datetime import datetime class Menu: def __init__(self): self.quitMenu = False def showMenu(self): print ''' A) Do A B) Do B ''' def askUser(self): current_date = datetime.now().isoformat(' ') choice = raw_input('%s > Please select option > ' % current_date) print return choice def stopMe(self): self.quitMenu = True def alive(self): return self.quitMenu == False def doMenuOnce(self): self.showMenu() choice = self.askUser() if not self.alive() : # Maybe somebody has tried to stop the menu while in askUser return if choice == 'A' : print 'A selected' elif choice == 'B' : print 'B selected' else : print 'ERR: choice %s not supported' % (choice) def forever(self): while self.alive(): self.doMenuOnce() from twisted.internet import reactor, threads import signal class MenuTwisted: def __init__(self, menu): self.menu = menu signal.signal(signal.SIGINT, self.interrupted) # Handle KeyboardInterrupt def interrupted(self, signum, stackframe): print 'Interrupted!' self.menu.stopMe() def doMenuOnce(self): threads.deferToThread(self.menu.doMenuOnce).addCallback(self.forever) def forever(self, res=None): if self.menu.alive() : reactor.callLater(0, self.doMenuOnce) else : reactor.callFromThread(reactor.stop) def run(self): self.forever() reactor.run()
我可以用两种不同的方式运行.
正常方式:
menu = Menu() menu.forever()
按下可^C
立即停止程序:
A) Do A B) Do B 2013-12-03 11:00:26.288846 > Please select option > ^CTraceback (most recent call last): File "twisted_keyboard_interrupt.py", line 72, inmenu.forever() File "twisted_keyboard_interrupt.py", line 43, in forever self.doMenuOnce() File "twisted_keyboard_interrupt.py", line 34, in doMenuOnce choice = self.askUser() File "twisted_keyboard_interrupt.py", line 22, in askUser choice = raw_input('%s > Please select option > ' % current_date) KeyboardInterrupt
正如所料.
扭曲的方式:
menu = Menu() menutw = MenuTwisted(menu) menutw.run()
按下^C
将产生:
A) Do A B) Do B 2013-12-03 11:04:18.678219 > Please select option > ^CInterrupted!
但askUser
实际上没有打断:我还需要按enter
的raw_input
完成.