首页 > 解决方案 > 如何组合线程?

问题描述

我正在尝试在 Raspberry Pi 上设置一个程序,该程序会将温度数据记录到 csv 作为主进程,如果温度超出范围,并行进程将发送带有时间间隔的电子邮件通知。我读到它可以用 Python 的 Threading 模块来完成,所以我正在尝试设置一个测试代码,并稍后为传感器优化它。我正在使用 random.randrange 模块进行虚拟读数,但是温度监控线程无法读取要激活的临时变量。“if”语句如何正确读取变量?

我尝试在 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)

标签: pythonmultithreading

解决方案


如果您收到关于temp未在电子邮件发送线程中定义的异常,我怀疑这是由于您正在运行的两个线程的时间问题。如果电子邮件线程在主线程第一次(模拟)温度读数之前运行,则该temp变量将不存在。这可能会发生也可能不会发生,这取决于线程计时的确切细节,这并不总是可预测的(尽管子线程在其父线程恢复之前运行一段时间可能很常见)。

有几种方法可以解决这个问题。一个简单的解决方法是在函数的启动中添加延迟,send_email以便运行它的线程将暂停足够长的时间,以便启动主线程中的温度读数。只需在循环sleep(1)开始之前添加类似或类似的行。while True

另一种选择是temp在启动电子邮件线程之前初始化为一些虚拟值。这样就会有一个变量可供读取,即使它实际上并不代表测量(或模拟)的温度。像temp = 21放置在线程启动循环之前某处的东西可以解决问题。

但我会注意到,在这种情况下使用线程的目的并不是很清楚。电子邮件线程或多或少地对每三次温度读数进行采样,但如果这是您想要的,您可以更明确地执行此操作。如果您不想以传感器循环的全速发送垃圾邮件,您还可以检查每个读数,并仅以更有限的速率发送电子邮件。我会考虑这样的事情:

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

推荐阅读