如何在经过一段时间后停止while循环?

Adi*_*ous 55 python python-2.7

如果它没有达到我想要的效果,我将如何在5分钟后停止while循环.

while true:
    test = 0
    if test == 5:
        break
    test = test - 1
Run Code Online (Sandbox Code Playgroud)

这段代码让我陷入了无尽的循环.

And*_*ark 99

请尝试以下方法:

import time
timeout = time.time() + 60*5   # 5 minutes from now
while True:
    test = 0
    if test == 5 or time.time() > timeout:
        break
    test = test - 1
Run Code Online (Sandbox Code Playgroud)

你可能还想在这里添加一个短暂的睡眠,这样这个循环不会占用CPU(例如time.sleep(1)在循环体的开头或结尾).

  • 在此解决方案中处理的条件太多.这应该进行优化,并将`while True`替换为`while time.time()<timeout`.请参阅以下第二个解决方案 (6认同)
  • 我使用`timeit.default_timer`,它始终是平台最精确的时钟。特别是,`time.time` 在 Windows 上只有 1/60 秒的粒度,如果你的超时时间很短,这可能不够。在 Python 3 上,还有 `time.monotonic`、`time.perf_counter` 和 `time.process_time`,它们可能会更好(我没有太多处理它们)。 (2认同)

Pet*_*mpl 33

while True:在这种情况下,您不需要使用循环.有一种更简单的方法可以直接使用时间条件:

import time

# timeout variable can be omitted, if you use specific value in the while condition
timeout = 300   # [seconds]

timeout_start = time.time()

while time.time() < timeout_start + timeout:
    test = 0
    if test == 5:
        break
    test -= 1
Run Code Online (Sandbox Code Playgroud)

  • 为什么你没有提到通过使用睡眠来阻止CPU被这个功能加载的可能性?此代码可能有效,但它会不必要地使用系统资源. (5认同)
  • 我不明白你所说的“好点”是什么意思。无论你把它放在哪里,检查何时跳出循环的逻辑都不会花费更多或更少的时间,这不是我要解决的问题。当意图不是永远停留在循环中时,像 `while True` 这样的结构不是好的形式。它可能会产生误导,并且有更好的方法来做到这一点,尽管从技术上讲,它可以用来实现相同的目标。这有点像用刀和勺吃牛排。 (2认同)
  • 这几乎肯定应该使用 [单调时间源](https://docs.python.org/3/library/time.html#time.monotonic)。 (2认同)

and*_*fsp 31

试试这个模块:http://pypi.python.org/pypi/interruptingcow/

from interruptingcow import timeout
try:
    with timeout(60*5, exception=RuntimeError):
        while True:
            test = 0
            if test == 5:
                break
            test = test - 1
except RuntimeError:
    pass
Run Code Online (Sandbox Code Playgroud)

问候

  • 这在 Windows 上不起作用,因为 Windows 不实现 SIGALRM。/sf/answers/3694599051/ (6认同)
  • 在我看来,这个解决方案应该是公认的答案.它表现得更好,即.在给定时间段内,更多代码在循环内执行. (2认同)
  • 考虑到缺少睡眠调用,这是否会导致CPU在循环中旋转? (2认同)

Ant*_*ony 9

在我看来,Petr Krampl的答案是最好的,但需要更多关于循环的性质以及如何优化系统的使用.发生在这个主题上的初学者可能会被问题和现有答案中的逻辑和算法错误进一步混淆.

首先,让我们看一下您最初编写代码时的代码:

while True:
    test = 0
    if test == 5:
        break
    test = test - 1
Run Code Online (Sandbox Code Playgroud)

如果你while True在循环上下文中说,通常你的意图是永远保持循环.如果这不是你的意图,你应该考虑循环结构的其他选项.Petr Krampl向您展示了一种处理此问题的完全合理的方法,对于可能阅读您的代码的其他人来说,这一点要清楚得多.此外,如果您需要重新访问代码以添加或修复某些内容,几个月后您会更清楚.编写良好的代码是您文档的一部分.通常有多种方法可以做,但这并不能使所有方式在所有情况下同等有效.while true这是一个很好的例子,特别是在这种情况下.

接下来,我们将查看原始代码中的算法错误.你在循环中做的第一件事是分配0 test.接下来你要做的是检查值是否test为5,除非你有多个线程修改相同的内存位置,否则情况永远不会是这种情况.线程不在讨论的范围内,但值得注意的是代码在技术上可以工作,但即使有多个线程也会丢失,例如信号量.无论如何,无论哨兵强迫无限循环,你都将永远坐在这个循环中.

test = test - 1无论它做什么,该语句都是无用的,因为变量在循环的下一次迭代开始时被重置.即使你改变它test = 5,循环仍然是无限的,因为每次重置该值.如果将初始化语句移到循环外部,那么它至少有机会退出.你可能想要的是这样的:

test = 0
while True:
    test = test - 1
    if test == 5:
        break
Run Code Online (Sandbox Code Playgroud)

循环中语句的顺序取决于程序的逻辑.然而,它将以任何顺序工作,这是主要观点.

下一个问题是从0开始的潜在和可能的逻辑错误,不断减去1,然后与正数进行比较.是的,只要您了解其含义,有时候这可能实际上就是您打算做的事情,但这很可能不是您的意图.当你到达像C和其他各种语言这样的整数范围的"底部"时,较新版本的python不会回滚.它将允许您继续减去1,直到您填满系统上的可用内存或至少分配给您的进程的内存.查看以下脚本和结果:

test = 0

while True:
    test  -= 1

    if test % 100 == 0:
        print "Test = %d" % test

    if test == 5:
        print "Test = 5"
        break
Run Code Online (Sandbox Code Playgroud)

产生这个:

Test = -100
Test = -200
Test = -300
Test = -400
...
Test = -21559000
Test = -21559100
Test = -21559200
Test = -21559300
...
Run Code Online (Sandbox Code Playgroud)

test永远不会是5,所以这个循环永远不会退出.

要添加到Petr Krampl的答案,这里的版本可能更接近你实际想要的版本,除了在一段时间后退出循环:

import time

test = 0
timeout = 300   # [seconds]

timeout_start = time.time()

while time.time() < timeout_start + timeout:
    if test == 5:
        break
    test -= 1
Run Code Online (Sandbox Code Playgroud)

它仍然不会基于值的值而中断test,但这是一个具有合理初始条件的完全有效的循环.进一步的边界检查可以帮助你无缘无故地避免执行一个很长的循环,例如检查循环进入时test的值是否小于5,这将立即打破循环.


应该提到的另一件事是没有其他答案得到解决.有时当你像这样循环时,你可能不想在整个分配的时间内消耗CPU.例如,假设您正在检查每秒更改的值的值.如果不引入某种延迟,则可以使用分配给进程的每个可用CPU周期.如果有必要,这很好,但是良好的设计将允许许多程序在您的系统上并行运行,而不会使可用资源负担过重.一个简单的睡眠语句将释放分配给您的进程的绝大多数CPU周期,以便其他程序可以正常工作.

以下示例不是很有用,但它确实展示了这个概念.假设您想要每秒打印一些东西.一种方法是这样的:

import time

tCurrent = time.time()

while True:
    if time.time() >= tCurrent + 1:
        print "Time = %d" % time.time()
        tCurrent = time.time()
Run Code Online (Sandbox Code Playgroud)

输出将是这样的:

Time = 1498226796
Time = 1498226797
Time = 1498226798
Time = 1498226799
Run Code Online (Sandbox Code Playgroud)

进程CPU使用情况如下所示:

在此输入图像描述

基本上没有工作,这是一个巨大的CPU使用量.这段代码对系统的其他部分更好:

import time

tCurrent = time.time()

while True:
    time.sleep(0.25) # sleep for 250 milliseconds
    if time.time() >= tCurrent + 1:
        print "Time = %d" % time.time()
        tCurrent = time.time()
Run Code Online (Sandbox Code Playgroud)

输出是一样的:

Time = 1498226796
Time = 1498226797
Time = 1498226798
Time = 1498226799
Run Code Online (Sandbox Code Playgroud)

并且CPU使用方式更低:

在此输入图像描述

  • @techkuz 这是一般计算的基本概念。跳过我的答案中的一些细节可能会给新程序员带来不完整的理解。我通常对 tl;drs 没什么意见,但我认为在这种情况下弊大于利。不过,我会在这条评论中写一条:“TL;DR:当您不需要经常使用资源时,使用 sleep() 或类似的方法来释放资源”。 (3认同)

Fab*_*ian 6

import time

abort_after = 5 * 60
start = time.time()

while True:
  delta = time.time() - start
  if delta >= abort_after:
    break
Run Code Online (Sandbox Code Playgroud)