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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/842557/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:57:52  来源:igfitidea点击:

How to prevent a block of code from being interrupted by KeyboardInterrupt in Python?

python

提问by saffsd

I'm writing a program that caches some results via the pickle module. What happens at the moment is that if I hit ctrl-c at while the dumpoperation is occurring, dumpgets interrupted and the resulting file is corrupted (i.e. only partially written, so it cannot be loaded again.

我正在编写一个程序,通过pickle 模块缓存一些结果。目前发生的情况是,如果我在dump操作发生时按 ctrl-c 键,则会dump被中断并且生成的文件已损坏(即仅部分写入,因此无法load再次编辑。

Is there a way to make dump, or in general a block of code, uninterruptable? My current workaround looks something like this:

有没有办法让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

It seems silly to restart the operation if it is interrupted, so I am searching for a way to defer the interrupt. How do I do this?

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

采纳答案by Unknown

Put the function in a thread, and wait for the thread to finish.

把函数放在一个线程中,等待线程结束。

Python threads cannot be interrupted except with a special C api.

除非使用特殊的 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

See how the interrupt was deferred until the thread finished?

看看中断是如何推迟到线程完成的?

Here it is adapted to your use:

它适合您的使用:

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

回答by Gary van der Merwe

The following is a context manager that attaches a signal handler for SIGINT. If the context manager's signal handler is called, the signal is delayed by only passing the signal to the original handler when the context manager exits.

以下是为 附加信号处理程序的上下文管理器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()

回答by Ignacio Vazquez-Abrams

Use the signalmodule to disable SIGINT for the duration of the process:

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

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

回答by Nadia Alramli

In my opinion using threads for this is an overkill. You can make sure the file is being saved correctly by simply doing it in a loop until a successful write was done:

在我看来,为此使用线程是一种矫枉过正。您可以通过简单地循环执行直到成功写入来确保文件被正确保存:

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

回答by Chris

This question is about blocking the KeyboardInterrupt, but for this situation I find atomic file writing to be cleaner and provide additional protection.

这个问题是关于阻止KeyboardInterrupt,但对于这种情况,我发现原子文件写入更干净并提供额外的保护。

With atomic writes either the entire file gets written correctly, or nothing does. Stackoverflow has a variety of solutions, but personally I like just using atomicwriteslibrary.

通过原子写入,要么整个文件被正确写入,要么什么都不做。Stackoverflow 有多种解决方案,但我个人喜欢只使用atomicwrites库。

After running pip install atomicwrites, just use it like this:

运行后pip install atomicwrites,只需像这样使用它:

from atomicwrites import atomic_write

with atomic_write(path, overwrite=True) as file:
    dump(obj, file)