如何防止代码块被Python中的KeyboardInterrupt中断?
我正在写一个程序,通过pickle模块缓存一些结果。 目前发生的情况是,如果我在dump操作发生时按ctrl-c,则dump会被打断并且结果文件被损坏(即仅部分写入,因此无法再次loaded)。
有没有办法使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
如果该操作被中断,重新启动该操作似乎很愚蠢,所以我正在寻找推迟该中断的方法。 我该怎么做呢?
saffsd asked 2020-02-06T03:57:26Z
5个解决方案
60 votes
以下是上下文管理器,它为SIGINT附加了信号处理程序。如果调用了上下文管理器的信号处理程序,则在上下文管理器退出时仅通过将信号传递给原始处理程序来延迟信号。
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()
Gary van der Merwe answered 2020-02-06T03:58:40Z
40 votes
将函数放在线程中,然后等待线程完成。
除非使用特殊的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
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()
Unknown answered 2020-02-06T03:58:20Z
25 votes
在此过程中,使用信号模块禁用SIGINT:
s = signal.signal(signal.SIGINT, signal.SIG_IGN)
do_important_stuff()
signal.signal(signal.SIGINT, s)
Ignacio Vazquez-Abrams answered 2020-02-06T03:59:01Z
10 votes
我认为为此使用线程是过大的。 您可以通过简单地循环执行直到成功写入来确保正确保存了文件:
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
Nadia Alramli answered 2020-02-06T03:59:21Z
1 votes
这个问题是关于阻止pip install atomicwrites的,但是对于这种情况,我发现原子文件写入更加简洁并提供了额外的保护。
使用原子写入,可以正确地写入整个文件,或者不执行任何操作。 Stackoverflow有多种解决方案,但个人而言,我只喜欢使用atomicwrites库。
运行pip install atomicwrites之后,只需像这样使用它:
from atomicwrites import atomic_write
with atomic_write(path, overwrite=True) as file:
dump(obj, file)
Chris answered 2020-02-06T03:59:50Z