无法设置python事件标志

时间:2018-08-07 22:56:26

标签: python events

我整天都在为此苦苦挣扎,我可以肯定这是一个线程问题,但我只是想不出什么问题。基本上,我的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._logger.info('-爱丽丝打招呼,模块已注册')

打印,意味着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()

1 个答案:

答案 0 :(得分:1)

这很像是您的队列出现计时问题。如果调用onConnected之后对onConnecting的调用发生得太快,则onConnectedonConnecting-> _connecting设置事件之前清除事件。

这就是我剥离班级以运行和测试它的方式(我删除了所有LED环材料,并向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甚至从队列中提取_start并对其进行处理之前清除事件。因此,在执行onConnecting时,_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

出于好奇,您实际上如何终止/加入线程?您是匿名创建的,因此我看不到如何处理它才能将其关闭。