Python 函数中未访问全局变量

Python global variable is not being accessed in function

这是我的 python 模块,运行 作为主线程中的两个线程。一个线程运行 monitor_wind(),每次旋转都会添加到 wind_count,另一个线程运行 calculate_speed() 以从计数中获取以 mph 为单位的风速,并将其添加到一个列表中,该列表稍后对平均风速进行平均英里/小时

我的问题是 calculate_speed() 似乎没有访问全局变量 wind_count,它始终为 0,即使 monitor_wind() 正在添加。但是它对 wind_list 所做的更改可以在 globals() 列表中看到。

如何让它访问全局变量?

from gpiozero import Button
import math
from time import sleep

wind_sensor = Button(6)
wind_count = 0
wind_list = []

def calculate_speed():
    while True:
        global wind_list, wind_count
        print(wind_count)
        radius_cm = 9.0
        cm_in_mile = 160934.4
        circumference_cm = (2 * math.pi) * radius_cm
        rotations = wind_count / 2.0
        dist_miles = (circumference_cm * rotations) / cm_in_mile
        speed = dist_miles / 5 # Divide distance by time, 5 seconds
        print(speed)
        wind_list.append(speed)
        wind_count = 0 # Reset wind count
        sleep(5)

def spin():
    global wind_count
    wind_count += 1

def monitor_wind():
    wind_sensor.when_pressed = spin

对我来说,这似乎不是您使用全局变量的问题,但我不鼓励使用全局变量,而是创建 class WindMonitor。如果您从多个线程访问一个变量,您也应该使用锁。

试试这个(我不得不在随机时间间隔调用自旋,因为我的设备上没有 gpios)。

wspeed.py

# from gpiozero import Button
import math
import random
import threading
from time import sleep

DEFAULT_WIND_SENSOR = None; # Button(6)

class WindMonitor:
    def __init__(self, button=DEFAULT_WIND_SENSOR):
        self.wind_count = 0
        self.wind_list = []
        self.button = button
        self.wind_count_lock = threading.Lock()
    
    def calculate_speed(self, stop_event):
        while True:
            with self.wind_count_lock:
                print(self.wind_count)
                radius_cm = 9.0
                cm_in_mile = 160934.4
                circumference_cm = (2 * math.pi) * radius_cm
                rotations = self.wind_count / 2.0
                dist_miles = (circumference_cm * rotations) / cm_in_mile
                speed = dist_miles / 5 # Divide distance by time, 5 seconds
                print(speed)
                self.wind_list.append(speed)
                self.wind_count = 0 # Reset wind count
            if stop_event.wait(5):
                return
    
    def spin(self):
        with self.wind_count_lock:
            self.wind_count += 1

    def monitor_wind(self):
        # self.button.when_pressed = self.spin
        while True:
            sleep(float(random.randint(1, 10)) / 10)
            self.spin()

__main__.py

import threading as th
import time
from wspeed import WindMonitor

if __name__ == '__main__':
    monitor = WindMonitor()
    stop_event = th.Event()
    th_wmonitor = th.Thread(target=monitor.monitor_wind, daemon=True)
    th_wspeed = th.Thread(target=monitor.calculate_speed, args=[stop_event], daemon=True)
    try:
        th_wspeed.start()
        th_wmonitor.start()
        while True: time.sleep(100)
    except (KeyboardInterrupt, SystemExit):
        stop_event.set()

编辑:解释停止事件

您的所有线程永远循环(主线程、th_wmonitorth_wspeed)。 您希望程序在主程序终止时退出。

当 python 退出时,它会等待所有非守护线程终止,因此您将它们设为守护线程是正确的做法。问题是 python 只会在有 单个 剩余守护线程时退出。因为两个守护线程都无限循环,所以您需要一种方法来告诉其中一个(或两个)程序何时退出。

实现此目的的最简单方法是使用 threading.Event 对象。 Event 是线程间通信的一种简单方式。它基本上是您在一个线程中设置并在另一个线程中签入的标志。通过在 main 中设置异常,您可以设置 threading.Eventstop_event 实例。这让任何有权访问 stop_event 的线程认为主线程已经退出,其他线程可以在它们准备终止时终止。

th_wspeed 需要在特定时间终止,因为您不想在打印语句的中间终止。出于这个原因,我将 th_wspeed 作为检查 stop_event 的对象。当 th_wspeed 发现 stop_event 已设置时,它会 returns,从而终止两个守护线程之一。那时,因为 python 看到只剩下一个守护线程,它会强制该线程终止,程序退出。

如果没有停止事件,程序将不会在您按下 CTRL+C 时终止。