如何在Python中安全地停止无限循环?

时间:2015-10-03 13:03:10

标签: python infinite-loop

我有一个在无限循环上运行的脚本,并将内容添加到数据库中并执行我无法中途停止的操作,因此我无法按ctrl + C和停止它。

我希望能够以某种方式停止while循环,但让它在停止之前完成它的最后一次迭代。

让我澄清一下:

我的代码看起来像这样:

while True:
    does something
    does more things
    does more things

我希望能够在结束或开始时中断while循环,但不能在执行操作之间中断,因为这样做会很糟糕。

如果我想继续,我不希望它在每次迭代后都问我。

感谢您的回答,我感激不尽,但我的实施似乎并没有起作用:

def signal_handler(signal, frame):
        global interrupted
        interrupted = True

class Crawler():
    def __init__(self):
    # not relevent

    def crawl(self):
        interrupted = False
        signal.signal(signal.SIGINT, signal_handler)
        while True:
            doing things
            more things

            if interrupted:
                print("Exiting..")
                break

当我按下ctr + c时,程序就一直无视我

4 个答案:

答案 0 :(得分:15)

你需要做的是抓住中断,设置一个标志,表示你被打断了然后继续工作,直到它有时间检查标志(在每个循环结束时)。因为python的try-except结构将放弃当前的循环运行,所以你需要设置一个合适的信号处理程序;它会处理中断,但让python继续从中断处继续。以下是:

import signal

import time   # For the demo only

def signal_handler(signal, frame):
    global interrupted
    interrupted = True

signal.signal(signal.SIGINT, signal_handler)


interrupted = False
while True:
    print("Working hard...")
    time.sleep(3)
    print("All done!")

    if interrupted:
        print("Gotta go")
        break

注意:

  1. 从命令行使用此命令。在IDLE控制台中,它会踩踏IDLE自己的中断处理。

  2. 更好的解决方案是"阻止" KeyboardInterrupt用于循环的持续时间,并在轮询中断时取消阻止。这是一些Unix风格的特征,但不是全部,因此python does not support it(参见第三个"一般规则")

  3. OP希望在课堂上这样做。但是信号处理系统调用中断函数,有两个参数:信号编号和指向堆栈帧的指针 - 没有self参数的位置可以访问类对象。因此,设置标志的最简单方法是使用全局变量。您可以使用闭包来装配指向本地上下文的指针(即,在__init__()中动态定义信号处理程序,但坦率地说,除非由于多线程或全局不可用,否则我不会感到烦恼。不管。

  4. 警告:如果您的进程处于系统调用过程中,处理信号可能会中断系统调用。因此,这可能对所有应用程序都不安全。更安全的替代方案是(a)不是依赖于信号,而是在每次循环迭代结束时使用非阻塞读取(并输入输入而不是命中^ C); (b)使用线程或进程间通信将工作者与信号处理隔离开来;或者(c)执行真实signal blocking的工作,如果你是在拥有它的操作系统上。所有这些都在某种程度上取决于操作系统,因此我将其留在那里。

答案 1 :(得分:10)

以下逻辑将帮助您完成此操作,

Enable Modules (C and Objective-C)

运行此操作时,请尝试按CTRL + C

答案 2 :(得分:0)

我希望以下代码可以帮助您:

#!/bin/python

import sys
import time
import signal

def cb_sigint_handler(signum, stack):
    global is_interrupted
    print "SIGINT received"
    is_interrupted = True

if __name__ == "__main__":
    is_interrupted = False
    signal.signal(signal.SIGINT, cb_sigint_handler)
    while(1):
        # do stuff here 
        print "processing..."
        time.sleep(3)
        if is_interrupted:
            print "Exiting.."
            # do clean up
            sys.exit(0)

答案 3 :(得分:0)

澄清@ praba230890的解决方案:interrupted变量未在正确的范围内定义。它是在crawl函数中定义的,根据程序根目录中处理程序的定义,处理程序无法将其作为全局变量到达。