在Python中打断time.sleep()

94 投票
7 回答
108013 浏览
提问于 2025-04-16 12:30

我想在使用time.sleep()的时候,按Ctrl+C可以中断它。

While 1:
    time.sleep(60)

在上面的代码中,当程序进入time.sleep这个函数时,需要整整60秒才能让Python处理Ctrl+C的中断。

有没有什么更好的方法,可以在time.sleep函数运行的时候就能中断它呢?

编辑

我是在一个老旧的系统上测试的,那个系统用的是Python 2.2,运行在Windows 2000上,这导致了很多麻烦。如果我用的是更新版本的Python,按Ctrl+C就能中断sleep()了。我临时用一个小技巧解决了这个问题,就是在一个循环里每次调用sleep(1),这样暂时解决了我的问题。

7 个回答

7

当用户按下中断键 Ctrl-C 时,就会出现一个叫做 KeyboardInterrupt 的异常。在 Python 中,这个异常是由一个叫 SIGINT 的信号引起的。这意味着,你可以使用信号模块来处理这个异常,按照你想要的方式来应对:

import signal

def handler(signum, frame):
    print("do whatever, like call thread.interrupt_main()")

signal.signal(signal.SIGINT, handler)
print("Waiting for SIGINT...")
signal.pause()

这样一来,当你收到键盘中断时,就可以做任何你想做的事情。

207

正确的做法是使用Python标准库中的threading.Event

当然,你可以把睡眠时间调得很短,这样就能在很短的时间内醒来,但如果你真的想每60秒运行一次循环呢?那你就得花更多的时间去判断是不是该运行了,还是继续睡觉。而且,你仍然是在阻塞,只不过时间短一些。相比之下,threading.Event就好用多了:

from threading import Event

exit = Event()

def main():
    while not exit.is_set():
      do_my_thing()
      exit.wait(60)

    print("All done!")
    # perform any cleanup here

def quit(signo, _frame):
    print("Interrupted by %d, shutting down" % signo)
    exit.set()

if __name__ == '__main__':

    import signal
    for sig in ('TERM', 'HUP', 'INT'):
        signal.signal(getattr(signal, 'SIG'+sig), quit);

    main()

当信号处理器调用exit.set()时,主线程的wait()调用会立即被打断。

现在,你可以使用Event来表示还有更多工作要做等等。但在这种情况下,它还可以方便地指示我们想要退出(比如while not exit.is_set()这一部分)。

你还可以选择在while循环后放置任何清理代码。

17

我不太明白这段代码的意思,不过如果需要的话,可以把 sleep() 的时间缩短一点,然后在它外面加个 for 循环:

for i in range(60):
   sleep(1)

用 try..except 来捕捉 KeyboardInterrupt 异常是很简单的。

撰写回答