首页 > 解决方案 > 无法设置 python 事件标志

问题描述

我整天都在为此苦苦挣扎,我很确定这是一个线程问题,但我就是不知道出了什么问题。基本上,我的 main.py 创建了一个“Neopixel”实例。那个新像素启动了一个运行 LED 环的线程。只要满足条件,一些环形动画就会运行,这与不会导致问题的简单 LED 闪烁不同。

为了处理这些情况,我使用了一个事件标志。当它是一个长动画时,它被设置为 true,当另一个 LED 状态开始时,它是未设置的,所以理论上它应该停止动画,因为它处于 while event.is_set() 循环中。但是......它永远不会被清除,即使我确实清除了它。

一些代码:

def __init__(self):
    self._logger = logging.getLogger('ProjectAlice')
    self._logger.info('Initializing Project Alice')

    self._leds = NeoPixels()
    self._leds.onStart()
    ....
    self._logger.info('Project Alice started')
    self._leds.onConnecting()
    self.greetAlice()
....
    elif message.topic == self._SUB_GREETING_BACK:
        self._state = State.REGISTERED
        self._logger.info('- Alice greeted back, module registered')
        self._leds.onConnected()

我已经删除了不相关的部分,但留下了 LED 部分。如我们所见,它启动,创建一个 Neopixels 实例,为 LED 调用 onStart(),然后调用 onConnect(),然后尝试通过 mqtt 到达主服务器。当主服务器回复时,我调用 onConnected()。但 LED 始终处于“onConnect()”状态,永远不会进入“onConnected()”状态。那里有一个 print('Done') ,它从不显示,但是当我 ctrl-c 程序时,它也会执行“onConnected”动画

不知何故,

self._animation.clear()

def onConnected(self):

没有注册,动画循环永远不会结束,但这

self._logger.info('- Alice 回来了,模块注册')

打印,意思是 onConnected() 被调用

类 NeoPixels(对象):

def __init__(self):
    self._running = True

    self._ring = Adafruit_NeoPixel(num=config.settings['ringLedCount'], pin=config.settings['ringLedPin'], brightness=125, strip_type=ws.SK6812_STRIP_RGBW)
    self._ring.begin()

    self._queue = Queue.Queue()
    self._animation = threading.Event()

    threading.Thread(target=self._run).start()

def onStart(self):
    self._running = True
    self._animation.clear()

    self._queue.put(self._start)

def onConnecting(self):
    self._animation.clear()
    self._queue.put(self._connecting)


def onConnected(self):
    self._animation.clear()
    self._queue.put(self._connected)

def _run(self):
    while self._running:
        func = self._queue.get()
        func()

def _start(self):
    for i in range(self._ring.numPixels()):
        self._setPixelColorRGB(i, 255, 0, 0)
        self._ring.show()
        time.sleep(10 / 1000.0)

    for i in range(self._ring.numPixels()):
        self._setPixelColorRGB(i, 0, 0, 0)
        self._ring.show()
        time.sleep(10 / 1000.0)

    time.sleep(0.25)

    for i in range(self._ring.numPixels()):
        self._setPixelColorRGB(i, 255, 0, 0)
        self._ring.show()
        time.sleep(1 / 1000.0)

def _connecting(self):
    self._animation.set()
    while self._animation.is_set():
        for i in range(self._ring.numPixels()):
            self._setPixelColorRGB(i, 255, 0, 0)
            self._ring.show()
            time.sleep(20 / 1000.0)
            threading.Timer(interval=20 / 1000.0, function=self._setPixelColorRGB, args=[i, 0, 0, 0]).start()
    print('done')

def _connected(self):
    for i in range(self._ring.numPixels()):
        self._setPixelColorRGB(i, 0, 128, 0)
        self._ring.show()

    time.sleep(1)
    self._clear()

标签: pythonevents

解决方案


这看起来很像您的队列的时间问题。如果在调用onConnected之后调用发生得太快,onConnectingonConnected在之前清除事件onConnecting->_connecting设置它。

这就是我剥离您的课程以运行和测试它的方式(我删除了所有 LED 环的东西并在 and 中添加了打印onConnected语句_run

import time, threading, queue

class NeoPixels:
    def __init__(self):
        self._running = True    
        self._queue = queue.Queue()
        self._animation = threading.Event()
        threading.Thread(target=self._run)

    def onStart(self):
        self._running = True
        self._animation.clear()
        self._queue.put(self._start)

    def onConnecting(self):
        self._animation.clear()
        self._queue.put(self._connecting)    

    def onConnected(self):
        print("called onConnected")
        self._animation.clear()
        self._queue.put(self._connected)


    def _run(self):
        while self._running:
            func = self._queue.get()
            print("now running {}".format(func.__qualname__))
            func()

    def _start(self):
        time.sleep(.5)

    def _connecting(self):
        self._animation.set()
        while self._animation.is_set():
            for i in range(5):
                time.sleep(20 / 1000.0)
        print('done')

    def _connected(self):
        for i in range(1):
            print("connected")
        time.sleep(1)

这是我运行它的方式:

leds = NeoPixels()
leds.onStart()
leds.onConnecting()
leds.onConnected()

这是输出:

called onConnected 
now running NeoPixels._start 
now running NeoPixels._connecting

如您所见,在从队列中获取并处理它onConnected之前,它被调用并清除事件。所以当被执行时,设置事件,因为在那之后没有清除它,它会无限期地运行。_run_startonConnecting_connecting

因此,更改onConnected为等待队列清除,如下所示:

def onConnected(self):
    while not self._queue.empty():
        time.sleep(.1)
    print("called onConnected")
    self._animation.clear()
    self._queue.put(self._connected)

将导致以下输出:

now running NeoPixels._start
now running NeoPixels._connecting
called onConnected
done
now running NeoPixels._connected
connected

出于好奇,您实际上如何终止/加入线程?您匿名创建它,所以我看不出您将如何处理它以在完成后关闭它。


推荐阅读