2

我试图运行延迟发送电子邮件,因为发送电子邮件的条件可能会在很长一段时间内处于开启状态,并且我不想接收和无限量的电子邮件警报......

为此,我正在尝试 threading.timer 给它一个延迟,并且每 15 分钟只发送一次电子邮件...我尝试了 .timer 对象的 900 秒长延迟,它可以工作(使用时间脚本)...但是当我运行它来发送电子邮件时,它首先发送电子邮件,然后进入计时器而不运行脚本的其他部分......电子邮件功能工作得很好......运行python 2.6.6

#!/usr/bin/env python

import time
import smtplib #for sending emails when warning
import threading

if True: #the possibility exists that the conditional is met several times thus sending lots of emails
    t = threading.Timer(300,send_email('Tank temperature Overheat',tank_temp))
    t.start() # after 300 seconds, the email will be sent but the script will keep running
print "rest of the script keeps running"
print "keeps running the scrpit and after 300s the email is sent"

关于为什么它不起作用或其他解决方法的任何想法?

在玩过它之后......它会进入睡眠状态,但会发送所有电子邮件......不是每X个.time设置的一封电子邮件......即

n=300

start = time.time()

while (time.time() - start < n):

    led_temp = 56

        if led_temp > 55:
        t = threading.Timer(100, lambda: send_email('Lights temperature Overheat',led_temp))
        t.start()

我不是每 100 秒收到一封电子邮件,而是在 300 秒后收到 36 封电子邮件.. ?? 知道为什么吗?(从下面的评论重新格式化)

在阅读了关于线程的答案后,我理解了这个问题......我仍然知道 python 并且从未使用过用户线程所以我想这是我在创建无数线程时收到的 36 封电子邮件的根本原因......我修复了它通过使用标志,并像这样测试代码:

def raise_flag():
    global start
    interval = 300
    if start > interval:
        start = 0
        flag = True
        print "Flag True, sending email"
        return flag
    else:
        flag = False
        start = start + 1
        print "Flag OFF", start
        time.sleep(1)
        return flag

led_temp = 27
while led_temp > 26:
    flag = raise_flag()
    if flag:
        send_email('Tank temperature Overheat',led_temp)
        flag = False
        print "Sent email"
4

3 回答 3

4

作为您的第二个参数,timer您应该传递一个可调用的,但在您的情况下,您正在调用该函数并将结果传递给threading.Timer. 您应该改用lambda表达式:

#!/usr/bin/env python

import time
import smtplib
import threading

if True:
    t = threading.Timer(300, lambda: send_email('Tank temperature Overheat',tank_temp))
    t.start() 
print "rest of the script keeps running"
print "keeps running the scrpit and after 300s the email is sent"

表达方式:

lambda: send_email('Tank temperature Overheat',tank_temp)

评估一个没有参数的函数,当调用时send_email使用该参数执行,而在你的代码中你有:

t = threading.Timer(300,send_email('Tank temperature Overheat',tank_temp))

这将首先评估所有参数,然后调用send_email然后创建Timer对象。


关于 300 秒内 36 封电子邮件的问题,在您的代码中:

n=300

start = time.time()

while (time.time() - start < n):

    led_temp = 56

        if led_temp > 55:
        t = threading.Timer(100, lambda: send_email('Lights temperature Overheat',led_temp))
        t.start()

while将在 300 秒的迭代中创建大量线程。我不知道你为什么认为这个循环应该每 100 秒向你发送一封电子邮件。每个线程都会在 100 秒后向您发送一封电子邮件,但线程数很多。

如果您只想发送 3 封电子邮件,那么您应该break在 3 次迭代后退出循环。此外,迭代可能太快了,因此所有计时器几乎会同时发送所有电子邮件,因为它们的超时时间几乎相等。

您可以使用以下代码查看此问题:

>>> import threading
>>> import threading
>>> def send_email(): print("email sent!")
... 
>>> for _ in range(5):
...     t = threading.Timer(7, send_email)
...     t.start()
... 
>>> email sent!
email sent!
email sent!
email sent!
email sent!

即使Timer创建了 5 个不同的 s,它们几乎同时超时,所以您会看到所有的email sent!同时出现。您可以修改超时以考虑到这一点:

>>> for i in range(5):
...     t = threading.Timer(7 + i, send_email)
...     t.start()
... 
>>> email sent!
email sent!
email sent!
email sent!
email sent!

在上面的代码中,您会看到email sent!一次出现一个,间隔大约为 1 秒。

最后,我要补充一点,您无法控制何时收到电子邮件。这由不同的服务以不同的方式处理,因此无法保证在运行您的代码时,收件人将每 100 秒收到一封电子邮件。

于 2013-06-25T17:44:56.753 回答
1

threading.Timer 可以在两种模式下运行:

第一个选项是使用方法提供的参数:

t = threading.Timer(interval=300, function=send_email, args=['Tank temperature Overheat', tank_temp])
t.start()

第二种选择是使用“lambda 函数”

t = threading.Timer(interval=300, lambda: send_email('Tank temperature Overheat', tank_temp))
t.start()
于 2019-04-08T09:41:42.070 回答
0

不确定这是否是您要查找的内容,但如果您的问题是计时器线程独立于主脚本运行,您可以join像这样使用该线程:

t.start()
t.join() # will wait until the thread `t` has finished

但是这种方式违背了在单独的线程中运行函数的目的。因此,您可能只想time.sleep在发送该电子邮件之前或之后的一段时间。

顺便说一句,请确保调用send_email('Tank temperature Overheat',tank_temp)实际返回一个函数,该函数将在计时器线程启动时调用并且不发送实际邮件。

于 2013-06-25T17:12:08.460 回答