简体   繁体   English

python asyncio.Event.wait()不响应event.set()

[英]python asyncio.Event.wait() not responding to event.set()

The plan is to have several IO routines running "concurrently" (specifically on a Raspberry Pi, manipulating IO pins and running an SPI interface at the same time). 计划是使多个IO例程“同时”运行(特别是在Raspberry Pi上,操作IO引脚并同时运行SPI接口)。 I try to use asyncio to make this happen. 我尝试使用asyncio来实现这一目标。 However, my simple try-out refuses to run. 但是,我的简单试用无法运行。
This is a reduced version of the code, leaving out the IO pin details: 这是该代码的简化版本,省略了IO引脚的详细信息:

"""\
Reduced problem representation:
this won't run because GPIO details have been left out
"""

import RPi.GPIO as gpio
import asyncio

GPIO_PB = 12         # Define pushbutton channel

async def payload():
    """ Provides some payload sequence using asyncio.sleep() """
    #Payload action
    await asyncio.sleep(1)
    #Payload action
    await asyncio.sleep(1)

class IOEvent(asyncio.locks.Event):
    """\
    Create an Event for asyncio, fired by a callback from GPIO
    The callback must take a single parameter: a gpio channel number
    """
    def __init__(self, ioChannel, loop):
        super().__init__(loop = loop)
        self.io = ioChannel

    def get_callback(self):
        "The callback is a closure that knows self when called"
        def callback( ch ):
            print("callback for channel {}".format(ch))
            if ch == self.io and not self.is_set():
                print(repr(self))
                self.set()
                print(repr(self))
        return callback

async def Worker(loop, event):
    print("Entering Worker: {}".format(repr(loop)))
    while loop.is_running():
        print("Worker waiting for {}".format(repr(event)))
        await event.wait()
        print("Worker has event")
        event.clear()
        await payload()
        print("payload ended")

loop = asyncio.get_event_loop()

# Create an event for the button
pb_event = IOEvent( GPIO_PB, loop)

# register the pushbutton's callback
# Pushing the button calls this callback function
gpio.add_event_callback( GPIO_PB, pb_event.get_callback() )

try:
    asyncio.ensure_future(Worker(loop, pb_event))
    loop.run_forever()
except KeyboardInterrupt:
    pass
finally:
    print("Closing Loop")
    loop.stop()
    loop.close()

The output I get is like this: 我得到的输出是这样的:

Entering Worker: <_UnixSelectorEventLoop running=True closed=False debug=False>
Worker waiting for <__main__.IOEvent object at 0x76a2a950 [unset]>
callback for channel 12
<__main__.IOEvent object at 0x76a2a950 [unset,waiters:1]>
<__main__.IOEvent object at 0x76a2a950 [set,waiters:1]>
callback for channel 12

These lines show the pushbutton repeatedly and correctly firing its callback routine. 这些行重复显示按钮并正确触发其回调例程。 The first time it calls the set() funtion as expected. 首次调用set()函数。 The event used for the wait() call and the set() call are the same. 用于wait()调用和set()调用的事件是相同的。 But the message "Worker has event" , after the await event.wait() call never appears. 但是,在await event.wait()调用之后,永远不会出现消息“ Worker has event”

I looked at PyQt5 and asyncio: yield from never finishes , but I do not see any other loops than the default loop. 我看了看PyQt5和asyncio:yield from never finishs ,但是除了默认循环,我看不到其他任何循环。

Why does wait() never return? 为什么wait()永不返回? How could I find out? 我怎么知道?

Callbacks set by add_event_callback must be called from a different thread, given that they are called without automatically. add_event_callback设置的add_event_callback必须从不同的线程调用,因为它们是自动调用的。 This means that you can't call set on an asyncio.Event to synchronize between them, since asyncio classes are not thread-safe by default. 这意味着您不能在asyncio.Event上调用set在它们之间进行同步,因为默认情况下asyncio类不是线程安全的。

To wake up an asyncio.Event from a different thread, you can pass event.set to loop.call_soon_threadsafe . 要从其他线程唤醒asyncio.Event ,可以将event.set传递给loop.call_soon_threadsafe In your case, you would change: 对于您的情况,您将更改:

self.set()

to: 至:

self._loop.call_soon_threadsafe(self.set)

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

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