python asyncio.Event.wait() 没有响应 event.set()
python asyncio.Event.wait() not responding to event.set()
计划有几个 IO 例程 运行ning "concurrently"(特别是在 Raspberry Pi 上,同时操作 IO 引脚和 运行ning 一个 SPI 接口时间)。我尝试使用 asyncio 来实现这一点。然而,我的简单尝试拒绝 运行.
这是代码的简化版本,省略了 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()
我得到的输出是这样的:
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
这些行显示按钮重复并正确触发其回调例程。它第一次按预期调用 set()
函数。 wait()
调用和 set()
调用使用的事件相同。但是 "Worker has event" 消息在 await event.wait()
调用之后从未出现。
我查看了 ,但除了默认循环我没有看到任何其他循环。
为什么 wait()
永远不会 return?我怎么知道?
add_event_callback
设置的回调是从不同的线程调用的,正如它们在“后台”自动调用所表明的那样。这意味着您不能直接从 gpio 回调在 asyncio.Event
上调用 set
,因为 asyncio 类 不是 thread-safe.
要从不同的线程唤醒 asyncio.Event
,您可以将 event.set
传递给 loop.call_soon_threadsafe
。在你的情况下,你会改变:
self.set()
至:
self._loop.call_soon_threadsafe(self.set)
计划有几个 IO 例程 运行ning "concurrently"(特别是在 Raspberry Pi 上,同时操作 IO 引脚和 运行ning 一个 SPI 接口时间)。我尝试使用 asyncio 来实现这一点。然而,我的简单尝试拒绝 运行.
这是代码的简化版本,省略了 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()
我得到的输出是这样的:
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
这些行显示按钮重复并正确触发其回调例程。它第一次按预期调用 set()
函数。 wait()
调用和 set()
调用使用的事件相同。但是 "Worker has event" 消息在 await event.wait()
调用之后从未出现。
我查看了
为什么 wait()
永远不会 return?我怎么知道?
add_event_callback
设置的回调是从不同的线程调用的,正如它们在“后台”自动调用所表明的那样。这意味着您不能直接从 gpio 回调在 asyncio.Event
上调用 set
,因为 asyncio 类 不是 thread-safe.
要从不同的线程唤醒 asyncio.Event
,您可以将 event.set
传递给 loop.call_soon_threadsafe
。在你的情况下,你会改变:
self.set()
至:
self._loop.call_soon_threadsafe(self.set)