【问题标题】:Python Execute a Function after timeoutPython在超时后执行一个函数
【发布时间】:2018-07-13 17:37:27
【问题描述】:

我想在 While true 循环中超时后启动一个函数,但代码不执行任何操作并跳出循环,我不知道为什么:/

这是我的代码

import requests
from threading import Timer

def timeout(flag):
            print("New Request")
            statuscode = requests.get("http://adslkfhdsjf.de").status_code
            if statuscode == 200 and flag == 0:
                print("Service available")
            #Testzwecke
            print("Flag: ", flag)
            flag = 0
            #Poste result to Backend
        elif statuscode == 200 and flag == 1: 
            print("Service is available now")
            print("Flag: ", flag)
            flag = 0
            #Email an User
            #Post Request
        elif statuscode != 200 and flag == 0:
            print("Service is not available")
            #Testzwecke
            print("Flag: ", flag)
            flag = 1
            #Email to User
            #Post Request
        else: 
            print("Service is not available")
            #Testzwecke
            print("Flag: ", flag)
            #Post Request
        Timer(10, timeout, flag)

timeout(0)

我希望例如每 10 秒执行一次超时。所以每隔 10 秒就会执行一个来自函数 timeout() 的条件。

但到目前为止它不起作用,控制台输出什么都没有:/

【问题讨论】:

  • 您在此处发布的代码仅定义了一个 main 函数,并且从不调用它。你的真实代码也是这样吗?
  • 把变量flag的声明和timeout的定义放在main外面。
  • 不管怎样,如果你解决了这个问题(通过在脚本末尾添加一个缩进的main()),你将遇到一个全新的问题:你正在创建并调用一个新的timeout尽可能快地反复运行。每个人都会创建一个Timer,它会创建一个新线程。所以你很快就会创建比你的操作系统可以处理的更多的线程。如果你很幸运,你会得到一个错误。如果你不走运,你的系统会慢慢爬起来,即使在你设法杀死脚本后也需要几分钟才能恢复。
  • @AfloroaieRobert 虽然这些都是合理的做法,但如何解决代码中的任何问题?每 10 秒构建一个新的函数对象的成本很小,但谁在乎呢? main 中的 flag 将被 timeout 中的 flag 隐藏,但对于全局 flag 也是如此。
  • @abarnert,我并没有试图解决问题,我试图建议对代码进行一些改进,因此是评论而不是答案。

标签: python


【解决方案1】:

你的第一个问题是你没有打电话给main()。通常,我只会添加一条评论来告诉您这一点,然后将问题作为错字关闭,但在您首先解决更大的问题之前,您不想解决这个问题。

您的代码试图以尽可能快的速度一遍又一遍地创建和调用新的timeout 函数。而timeout 函数所做的第一件事就是创建一个新的Timer 对象。这是一个新线程。

因此,您生成新线程的速度与 Python 允许的一样快,这意味着在很短的时间内,您将拥有比操作系统处理能力更多的线程。如果你很幸运,那将意味着你得到一个异常并且你的程序退出。如果您不走运,这将意味着您的系统会随着内核开始将线程堆栈交换到磁盘而慢下来,而且,即使您设法终止程序,也可能需要几分钟才能恢复。

实际上,while 循环在这里没有任何理由。每个Timer 安排下一个Timer,因此它将永远运行。而且这样一次只有 2 个线程处于活动状态。

但首先,Timer 甚至没有理由。您不想在请求之间等待 10 秒时做任何事情,那么为什么不直接使用 sleep

import time
import requests

def main():
    flag = 0
    while True:
        print("New Request")
        statuscode = requests.get("http://google.de").status_code
        if statuscode == 200 and flag == 0:
            print("Service available")
            # etc.
        time.sleep(10)

main()

您的代码还有另一个问题:您在 timeout 中定义了一个名为 flag 的局部变量,但随后您尝试在 flag == 0 检查中使用它,然后再分配给它。这将引发UnboundLocalError。您碰巧在main 中也有一个名为flag 的局部变量这一事实并没有什么不同。要解决此问题,您必须执行以下操作之一:

  • flag 作为Timer 的参数传入,以作为参数传递给每个timeout 调用。 (可能是最好的。)
  • nonlocal flag 声明添加到timeout,使其成为您定义的所有timeout 函数共享的闭包单元。 (不错,但不是最惯用的解决方案。)
  • 在两个函数中添加global flag 声明,这样它就变成了全宇宙所有人共享的全局变量。 (这么简单的程序可能很好,但至少不是一个好习惯。)

但是,一旦我们摆脱了线程,我们也摆脱了函数,所以只有一个本地flag,所以问题一开始就不会出现。

【讨论】:

  • 嗨,首先感谢您的准确回答 :) 新手的一个问题,我如何为计时器做到这一点,我不太了解 python 中的计时器,文档也没有帮助我。在这种情况下,我会像这样在我的 main 中传递标志吗?主要(标志)
  • @Kai A Timer 需要一个超时、一个函数以及任意数量的 args 和 kwargs。因此,例如,Timer(20, timeout, flag) 将在 20 秒后调用 timeout(flag)Timer(20, print, 20, 30, sep=',') 将在 20 秒后调用 print(20, 30, sep=',')
  • 那么,我可以用参数调用而不是 main 定时器函数吗?
  • @Kai 是的,如果你想使用 Timer,你真的不需要main,你可以直接打电话给timeout。如果您将标志作为参数传递,您的顶级代码将调用timeout(0) 以传递flag 的初始值,然后在timeout 的末尾执行Timer(10, timeout, flag) 传递下一次调用的新值。
  • 我已经编辑了代码并且定时器函数在 10 秒后不会调用自己:/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-16
  • 2016-06-18
  • 1970-01-01
相关资源
最近更新 更多