Python,threading.timer对象不会运行函数计时器?

时间:2013-06-25 16:55:36

标签: python function timer delay sleep

我试图运行发送延迟的电子邮件,因为发送电子邮件的条件可能会开启很长一段时间,我不想收到无限量的电子邮件提醒...

为此,我正在尝试使用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次设置一次电子邮件...即

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"

3 个答案:

答案 0 :(得分:2)

作为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退出循环。此外,迭代可能太快,因此所有计时器几乎会立即发送所有电子邮件,因为它们的超时几乎相等。

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

>>> 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!

即使创建了5个不同的Timer,它们几乎会同时超时,因此您会看到所有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秒会收到一封电子邮件。

答案 1 :(得分:0)

不确定这是否是您正在寻找的,但如果您的问题是计时器线程独立于主脚本运行,您可以join该线程如此:

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

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

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

答案 2 :(得分:0)

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()