如何在Python中安全地停止无限循环? [英] How to stop an infinite loop safely in Python?

查看:235
本文介绍了如何在Python中安全地停止无限循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个可以无限循环运行的脚本,可以将其添加到数据库中,并且可以执行一些我不能只停止一半的操作,所以我不能只按ctrl + C并停止它.

I've got a script that runs on a infinite loop and adds things to a database and does things that I can't just stop halfway through so I can't just press ctrl+C and stop it.

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

I want to be able to somehow stop a while loop but let it finish it's last iteration before it stops.

让我澄清一下:

我的代码如下:

while True:
    does something
    does more things
    does more things

我希望能够在结束时或开始时中断while循环,但不要在做事之间中断,因为那样会很糟糕.

I want to be able to interrupt the while loop at the end, or the beginning, but not between doing things because that would be bad.

我不想让它在每次迭代后问我是否要继续.

and I don't want it to ask me after every iteration if i want to continue.

非常感谢,我非常感谢,但是我的实现似乎没有效果:

thanks for the great answers, i'm super grateful but my implementation doesn't seem to be working:

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时,程序会一直不理我

when I press ctr+c the program just keeps going ignoring me

推荐答案

您需要做的是捕获中断,设置一个标志,表明您已被中断,但是继续进行操作,直到检查该标志为止(在末尾).每个循环).由于python的try-except构造将放弃当前的循环运行,因此您需要设置适当的信号处理程序;它会处理中断,但随后让python从中断处继续执行.方法如下:

What you need to do is catch the interrupt, set a flag saying you were interrupted but then continue working until it's time to check the flag (at the end of each loop). Because python's try-except construct will abandon the current run of the loop, you need to set up a proper signal handler; it'll handle the interrupt but then let python continue where it left off. Here's how:

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自己的中断处理.

  1. Use this from the command line. In the IDLE console, it'll trample on IDLE's own interrupt handling.

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

A better solution would be to "block" KeyboardInterrupt for the duration of the loop, and unblock it when it's time to poll for interrupts. This is a feature of some Unix flavors but not all, hence python does not support it (see the third "General rule")

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

The OP wants to do this inside a class. But the interrupt function is invoked by the signal handling system, with two arguments: The signal number and a pointer to the stack frame-- no place for a self argument giving access to the class object. Hence the simplest way to set a flag is to use a global variable. You can rig a pointer to the local context by using closures (i.e., define the signal handler dynamically in __init__(), but frankly I wouldn't bother unless a global is out of the question due to multi-threading or whatever.

注意事项:如果您的进程处于系统调用的中间,则处理信号可能会中断系统调用.因此,这可能不适用于所有应用程序.更安全的选择是(a)在每个循环迭代的末尾使用非阻塞读取(而不是依赖信号)(并键入输入而不是^ C); (b)使用线程或进程间通信将工作人员与信号处理隔离开;或(c)如果您使用的是真正的信号阻止,请执行该工作.它们都在某种程度上依赖于操作系统,因此我将其保留.

Caveat: If your process is in the middle of a system call, handling an signal may interrupt the system call. So this may not be safe for all applications. Safer alternatives would be (a) Instead of relying on signals, use a non-blocking read at the end of each loop iteration (and type input instead of hitting ^C); (b) use threads or interprocess communication to isolate the worker from the signal handling; or (c) do the work of implementing real signal blocking, if you are on an OS that has it. All of them are OS-dependent to some extent, so I'll leave it at that.

这篇关于如何在Python中安全地停止无限循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆