如何防止由Python中的KeyboardInterrupt打断一段代码?
我正在编写一个程序,通过pickle模块caching一些结果。 现在发生的情况是,如果在dump
操作发生时按ctrl-c,则dump
会中断,并且生成的文件已损坏(即只能部分写入,因此无法再次load
。
有没有办法使dump
,或一般来说,一块代码,不间断? 我目前的解决方法看起来像这样:
try: file = open(path, 'w') dump(obj, file) file.close() except KeyboardInterrupt: file.close() file.open(path,'w') dump(obj, file) file.close() raise
如果中断,重启操作似乎很愚蠢,所以我正在寻找延迟中断的方法。 我该怎么做呢?
把函数放在一个线程中,等待线程完成。
除了特殊的C API之外,Python线程不能被打断。
import time from threading import Thread def noInterrupt(): for i in xrange(4): print i time.sleep(1) a = Thread(target=noInterrupt) a.start() a.join() print "done" 0 1 2 3 Traceback (most recent call last): File "C:\Users\Admin\Desktop\test.py", line 11, in <module> a.join() File "C:\Python26\lib\threading.py", line 634, in join self.__block.wait() File "C:\Python26\lib\threading.py", line 237, in wait waiter.acquire() KeyboardInterrupt
看看中断是如何推迟的,直到线程结束?
这里适合你的使用:
import time from threading import Thread def noInterrupt(path, obj): try: file = open(path, 'w') dump(obj, file) finally: file.close() a = Thread(target=noInterrupt, args=(path,obj)) a.start() a.join()
以下是连接SIGINT
的信号处理程序的上下文pipe理器。 如果调用上下文pipe理器的信号处理程序,则只有当上下文pipe理器退出时才将信号传递给原始处理程序,从而延迟信号。
import signal import logging class DelayedKeyboardInterrupt(object): def __enter__(self): self.signal_received = False self.old_handler = signal.signal(signal.SIGINT, self.handler) def handler(self, sig, frame): self.signal_received = (sig, frame) logging.debug('SIGINT received. Delaying KeyboardInterrupt.') def __exit__(self, type, value, traceback): signal.signal(signal.SIGINT, self.old_handler) if self.signal_received: self.old_handler(*self.signal_received) with DelayedKeyboardInterrupt(): # stuff here will not be interrupted by SIGINT critical_code()
使用信号模块在整个过程中禁用SIGINT:
s = signal.signal(signal.SIGINT, signal.SIG_IGN) do_important_stuff() signal.signal(signal.SIGINT, s)
在我看来,使用线程这是一个矫枉过正。 你可以确保文件正在被正确保存,只需要一个循环,直到成功完成写入:
def saveToFile(obj, filename): file = open(filename, 'w') cPickle.dump(obj, file) file.close() return True done = False while not done: try: done = saveToFile(obj, 'file') except KeyboardInterrupt: print 'retry' continue