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

dav*_*gri 13 python infinite-loop

我有一个在无限循环上运行的脚本,并将数据添加到数据库中并执行我不能只停留一半的事情,所以我不能只按ctrl + C并停止它.

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

让我澄清一下:

我的代码看起来像这样:

while True:
    does something
    does more things
    does more things
Run Code Online (Sandbox Code Playgroud)

我希望能够在结束或开始时中断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
Run Code Online (Sandbox Code Playgroud)

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

ale*_*xis 16

您需要做的是捕获中断,设置一个标记表示您被中断,然后继续工作,直到检查标志(在每个循环结束时).因为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
Run Code Online (Sandbox Code Playgroud)

笔记:

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

  2. 更好的解决方案是在循环期间"阻塞"KeyboardInterrupt,并在轮询中断时取消阻止.这是一些Unix风格的功能,但不是全部,因此python 不支持它(参见第三个"一般规则")

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

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


pra*_*890 10

以下逻辑将帮助您做到这一点,

import signal
import sys
import time

run = True

def signal_handler(signal, frame):
    global run
    print "exiting"
    run = False

signal.signal(signal.SIGINT, signal_handler)
while run:
    print "hi"
    time.sleep(1)
    # do anything
    print "bye"
Run Code Online (Sandbox Code Playgroud)

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