简体   繁体   English

如何组合线程?

[英]How to combine threads?

I am trying to set up a program on Raspberry Pi that would log temperature data to a csv as a main process and a parallel process would send e-mail notifications with time intervals if the temperature is out of margins. 我正在尝试在Raspberry Pi上设置一个程序,该程序会将温度数据记录到csv中作为主要过程,并且如果温度超出裕度,则并行过程将按时间间隔发送电子邮件通知。 I read that it could be done with Python's Threading module, so I am trying to set - up a test code and will optimize it for the sensors later. 我读到它可以用Python的Threading模块完成,因此我试图设置-建立测试代码,并将在以后的传感器中对其进行优化。 I am using the random.randrange module for virtual readings, however the temperature monitoring thread cannot read the temp variable to be activated. 我正在使用random.randrange模块进行虚拟读数,但是温度监视线程无法读取要激活的temp变量。 How can the "if" statement read the variable correctly? “ if”语句如何正确读取变量?

I have tried setting up temp outside of the while True loop and activating the thread after the loop 我试图在while True循环之外设置temp并在循环后激活线程

import time
import csv
import random
import smtplib
import threading

path = 'C:/Users/saint/.PyCharmCE2019.1/config/scratches/log.csv'
templogfile = open(path,'a')

sender = 'sender@gmail.com'
receivers = ['receiver@hotmail.com']

def send_email():
    while True: 
        print("mail module")
        if temp <= 20:
            try:
                smtpObj = smtplib.SMTP('smtp.gmail.com', 587)
                smtpObj.starttls()
                smtpObj.login('sender@gmail.com', 'senderpassword')
                smtpObj.sendmail(sender, receivers, message)
                print("Successfully sent email")
                time.sleep(15)
            except smtplib.SMTPException:
                print("Error: unable to send email")
                time.sleep(15)
Threads = []
for i in range(1):
    t = threading.Thread(target=send_email)
    t.daemon = True
    t.start()

with open(path,'a') as csvfile:
    tempwriter = csv.writer(csvfile)
    tempwriter.writerow(['Time', 'Temperature C'])
    while True:
        time_now = time.asctime()
        temp = random.randrange(-10,20)
        tempwriter.writerow([time_now, temp])
        templogfile.close()
        print('Time:', time_now, 'Temperature:', temp)
        csvfile.flush()
        time.sleep(5)

I'm not sure that a separate thread is needed to send emails here. 我不确定是否需要单独的线程才能在此处发送电子邮件。 Why not just: 为什么不只是:

def send_email(temp):
    print("mail module")
    if temp <= 20:
        try:
            smtpObj = smtplib.SMTP('smtp.gmail.com', 587)
            smtpObj.starttls()
            smtpObj.login('sender@gmail.com', 'senderpassword')
            smtpObj.sendmail(sender, receivers, message)
            print("Successfully sent email")
        except smtplib.SMTPException:
            print("Error: unable to send email")

with open(path,'a') as csvfile:
    tempwriter = csv.writer(csvfile)
    tempwriter.writerow(['Time', 'Temperature C'])
    while True:
        time_now = time.asctime()
        temp = random.randrange(-10,20)
        send_email(temp)
        tempwriter.writerow([time_now, temp])
        templogfile.close()
        print('Time:', time_now, 'Temperature:', temp)
        csvfile.flush()
        time.sleep(5)

If you are getting an exception about temp not being defined in your email-sending thread, I suspect it is due to the timing of the two threads you're running. 如果您在发送电子邮件的线程中没有定义有关temp的异常,我怀疑这是由于您正在运行的两个线程的时间安排所致。 If the email thread runs before the main thread makes its first (simulated) temperature reading, the temp variable won't exist yet. 如果电子邮件线程在主线程进行其第一个(模拟)温度读数之前运行,则temp变量尚不存在。 This may or may not happen, it depends on the exact details of the thread timings, which are not always predictable (though it may be very common for the child thread to run for a while before its parent is resumed). 这可能会或可能不会发生,这取决于线程时序的确切细节,这些细节并不总是可以预测的(尽管子线程在恢复其父线程之前运行一段时间可能是很常见的)。

There are a few ways to work around this. 有几种方法可以解决此问题。 One easy fix would be to add a delay into the start of the send_email function so that the thread running it will pause for long enough for the temperature readings in the main thread to have been started. 一个简单的解决方法是在send_email函数的启动中添加一个延迟,以便运行它的线程将暂停足够长的时间,以便启动主线程中的温度读数。 Just add a line like sleep(1) or similar before the start of the while True loop. 只需在while True循环开始之前添加一行sleep(1)或类似内容。

Another option would be to initialize temp to some dummy value before you start the email thread. 另一个选择是在启动电子邮件线程之前将temp初始化为某个虚拟值。 That way there would be a variable to read, even if it didn't actually represent a measured (or simulated) temperature. 这样,即使实际上并不能代表测量(或模拟)的温度,也可以读取一个变量。 Something like temp = 21 placed somewhere before the thread starting loop would do the trick. 将诸如temp = 21放在线程启动循环之前的某个位置即可解决问题。

But I'd note that it's not really clear what the purpose of using threads is in this situation. 但是我要指出的是,在这种情况下,使用线程的目的到底是什么还不清楚。 The email thread is more or less sampling every third temperature reading, but you could do that more explicitly if that's what you want. 电子邮件线程或多或少会每三个温度读数采样一次,但是如果您想要的话,您可以更明确地进行此操作。 You could also inspect every reading, and send emails only at some more limited rate, if you don't want to spam them out at the full speed of the sensor loop. 如果您不想以传感器循环的全速发送垃圾邮件,则还可以检查每个读数,并仅以更有限的速率发送电子邮件。 I'd consider something like this: 我会考虑这样的事情:

email_flag = False
count = 0
while True:
    time_now = time.asctime()
    temp = random.randrange(-10,20)
    tempwriter.writerow([time_now, temp])

    if temp <= 20:
        email_flag = True

    count += 1
    if email_flag and count >= 3:
        send_email() # unconditionally sends the message
        email_flag = False
        count = 0

I think the problem is because one of the threads is trying to access the global temp variable before it's created. 我认为问题是因为其中一个线程正在尝试在创建全局temp变量之前对其进行访问。 A very simple solution would be to create it near the top of the module with: 一个非常简单的解决方案是使用以下命令在模块顶部附近创建它:

temp = None

and then add a short preamble to the thread function that makes it wait until the variable been set to a value: 然后在线程函数中添加一个简短的序言,使其等待直到变量被设置为值:

def send_email():
   # Wait for global to have data (ADDED)
   while temp is None:
       time.sleep(.5)
   while True:
       print("mail module")
       if temp <= 20:
           try:
               smtpObj = smtplib.SMTP('smtp.gmail.com', 587)
               smtpObj.starttls()
               smtpObj.login('sender@gmail.com', 'senderpassword')
               smtpObj.sendmail(sender, receivers, message)
               print("Successfully sent email")
               time.sleep(15)
           except smtplib.SMTPException:
               print("Error: unable to send email")
               time.sleep(15)

Another alternative would be to just set it to some numeric value (that won't be logged) which wouldn't require the preamble to be added since the variable will always exist. 另一种选择是将其设置为某个数字值(不会记录),因为变量将始终存在,因此不需要添加前导。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM