我正在编写一个通过pickle模块缓存一些结果的程序。目前发生的情况是,如果我在dump
操作发生时按下ctrl-c,dump
被中断并且生成的文件被破坏(即只是部分写入,所以它不能是{{ 1}再次编辑。
有没有办法让load
或一般的代码块不间断?我目前的解决方法看起来像这样:
dump
如果操作被中断,重新启动操作似乎很愚蠢,所以我正在寻找一种推迟中断的方法。我该怎么做?
答案 0 :(得分:58)
以下是为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()
答案 1 :(得分:37)
将函数放入线程中,等待线程完成。
除了特殊的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()
答案 2 :(得分:24)
使用signal模块在整个过程中禁用SIGINT:
s = signal.signal(signal.SIGINT, signal.SIG_IGN)
do_important_stuff()
signal.signal(signal.SIGINT, s)
答案 3 :(得分:9)
在我看来,使用线程是一种矫枉过正。您只需在循环中执行此操作即可确保正确保存文件,直到成功完成写入:
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
答案 4 :(得分:1)
这个问题是关于阻止KeyboardInterrupt
的,但是对于这种情况,我发现原子文件写入更加简洁并提供了额外的保护。
使用原子写入,要么正确地写入了整个文件,要么什么也没做。 Stackoverflow有一个variety of solutions,但是我个人更喜欢只使用atomicwrites库。
运行pip install atomicwrites
后,只需像这样使用它:
from atomicwrites import atomic_write
with atomic_write(path, overwrite=True) as file:
dump(obj, file)
答案 5 :(得分:0)
一种通用方法是使用上下文管理器,该上下文管理器接受一组信号来挂起:
import signal
from contextlib import contextmanager
@contextmanager
def suspended_signals(*signals):
"""
Suspends signal handling execution
"""
signal.pthread_sigmask(signal.SIG_BLOCK, set(signals))
try:
yield None
finally:
signal.pthread_sigmask(signal.SIG_UNBLOCK, set(signals))