如何防止Python中的代码块被KeyboardInterrupt中断?

2024-03-29 13:00:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在编写一个程序,通过pickle模块缓存一些结果。目前发生的情况是,如果我在执行dump操作时按ctrl-c at,则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

如果操作被中断,重新启动它似乎很愚蠢,所以我正在寻找一种推迟中断的方法。我该怎么做?


Tags: 模块文件path方法程序objclose情况
3条回答

将函数放入线程中,并等待线程完成。

除非使用特殊的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附加一个信号处理程序。如果调用了上下文管理器的信号处理程序,则只有在上下文管理器退出时将信号传递给原始处理程序,信号才会延迟。

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()

使用signal模块在进程期间禁用SIGINT:

s = signal.signal(signal.SIGINT, signal.SIG_IGN)
do_important_stuff()
signal.signal(signal.SIGINT, s)

相关问题 更多 >