Python 将asyncio与外部库中的非异步回调方法一起使用
我正在使用python库处理Raspberry Pi上的简单GPIO设备(我在这里使用MotionSensor作为示例):Python 将asyncio与外部库中的非异步回调方法一起使用,python,asynchronous,python-asyncio,gpiozero,Python,Asynchronous,Python Asyncio,Gpiozero,我正在使用python库处理Raspberry Pi上的简单GPIO设备(我在这里使用MotionSensor作为示例): 导入异步IO 从gpiozero导入运动传感器 类MotionSensorHandler(): __whenMotionCallback=None def u uu init uuuuu(self、pin、whenMotionCallback): #whenMotionCallback是一个异步函数 self.\uuuWhenMotionCallback=whenMotio
导入异步IO
从gpiozero导入运动传感器
类MotionSensorHandler():
__whenMotionCallback=None
def u uu init uuuuu(self、pin、whenMotionCallback):
#whenMotionCallback是一个异步函数
self.\uuuWhenMotionCallback=whenMotionCallback
#只需使用gpiozero lib初始化传感器
运动传感器=运动传感器(针脚)
#检测到运动时调用的方法
motionSensor.when\U MOTIONE=self.whenMotion
异步def whenMotion(自):
等待self.\uuuu whenMotionCallback()
我这里的问题是,我试图给一个async
函数提供对motionSensor.when\u motion
的回调
所以我得到了一个错误,whenMotion
函数是async
但从不wait
但实际上我不能等待它:
#将无法工作,因为MotionSensor()未使用asyncio
motionSensor.when\u motion=等待self.whenMotion
您知道如何将我的
async
函数分配给一个none-one吗?如果您使用协程执行此操作,则需要获取并运行事件循环。我假设您使用的是python 3.7,在这种情况下,您可以执行以下操作:
import asyncio
from gpiozero import MotionSensor
class MotionSensorHandler():
__whenMotionCallback = None
def __init__(self, pin, whenMotionCallback):
# whenMotionCallback is an async function
self.__whenMotionCallback = whenMotionCallback
# Just init the sensor with gpiozero lib
motionSensor = MotionSensor(pin)
# Method to call when motion is detected
loop = asyncio.get_event_loop()
motionSensor.when_motion = loop.run_until_complete(self.whenMotion())
loop.close()
async def whenMotion(self):
await self.__whenMotionCallback()
如果您使用的是python 3.8,那么只需使用
asyncio.run
,而不是所有显式地获取和运行事件循环。如果您使用协同程序来实现这一点,则需要获取和运行事件循环。我假设您使用的是python 3.7,在这种情况下,您可以执行以下操作:
import asyncio
from gpiozero import MotionSensor
class MotionSensorHandler():
__whenMotionCallback = None
def __init__(self, pin, whenMotionCallback):
# whenMotionCallback is an async function
self.__whenMotionCallback = whenMotionCallback
# Just init the sensor with gpiozero lib
motionSensor = MotionSensor(pin)
# Method to call when motion is detected
loop = asyncio.get_event_loop()
motionSensor.when_motion = loop.run_until_complete(self.whenMotion())
loop.close()
async def whenMotion(self):
await self.__whenMotionCallback()
如果您使用的是python 3.8,则只需使用
asyncio.run
,而不是所有显式获取和运行事件循环。如果这是在循环中运行的,并且在运动不需要返回值时,可以执行以下操作:
。。。
motionSensor.when\U MOTIONE=self.whenMotion
def启动时(自身):
asyncio.Survey_future(self.u whenMotionCallback())
这将在事件循环中安排异步回调,并使库的调用代码保持同步。如果这是在循环中运行的,并且当\u motion
不需要返回值时,可以执行以下操作:
。。。
motionSensor.when\U MOTIONE=self.whenMotion
def启动时(自身):
asyncio.Survey_future(self.u whenMotionCallback())
这将在事件循环中安排异步回调,并保持库的调用代码同步。因此,经过研究,我发现我必须创建一个新的异步IO循环,以非异步方法执行异步脚本。因此,现在我的whenMotion()
方法不再是async
,而是使用sure\u future()
执行一个
导入异步IO
从gpiozero导入运动传感器
类MotionSensorHandler():
__whenMotionCallback=None
def u uu init uuuuu(self、pin、whenMotionCallback):
#whenMotionCallback是一个异步函数
self.\uuuWhenMotionCallback=whenMotionCallback
#只需使用gpiozero lib初始化传感器
运动传感器=运动传感器(针脚)
#检测到运动时调用的方法
motionSensor.when\U MOTIONE=self.whenMotion
def启动时(自身):
#创建新的异步IO循环
loop=asyncio.new\u event\u loop()
asyncio.set\u event\u循环(循环)
future=asyncio。确保_future(self._executewhenomationcallback())#执行异步方法
循环。运行_直到_完成(未来)
loop.close()
异步定义\uuuu执行WhenMotionCallback(自):
等待self.\uuuu whenMotionCallback()
所以经过研究,我发现我必须创建一个新的asyncio循环,以非异步方法执行异步脚本。因此,现在我的whenMotion()
方法不再是async
,而是使用sure\u future()
执行一个
导入异步IO
从gpiozero导入运动传感器
类MotionSensorHandler():
__whenMotionCallback=None
def u uu init uuuuu(self、pin、whenMotionCallback):
#whenMotionCallback是一个异步函数
self.\uuuWhenMotionCallback=whenMotionCallback
#只需使用gpiozero lib初始化传感器
运动传感器=运动传感器(针脚)
#检测到运动时调用的方法
motionSensor.when\U MOTIONE=self.whenMotion
def启动时(自身):
#创建新的异步IO循环
loop=asyncio.new\u event\u loop()
asyncio.set\u event\u循环(循环)
future=asyncio。确保_future(self._executewhenomationcallback())#执行异步方法
循环。运行_直到_完成(未来)
loop.close()
异步定义\uuuu执行WhenMotionCallback(自):
等待self.\uuuu whenMotionCallback()
当设置When_motion属性时,gpiozero将创建一个执行回调的新线程(这一点没有很好的文档记录)。如果回调应该在主异步IO循环中执行,那么需要将控制权传递回主线程
这个方法可以帮你做到这一点。本质上,当等待发生时,它将回调添加到主异步IO循环调用的任务列表中
但是,异步IO循环对于每个线程都是本地的:请参阅
因此,当在主异步线程中创建gpiozero对象时,需要在调用回调时使该循环对象对该对象可用
对于调用asyncio MQTT方法的PIR,我是这样做的:
class PIR:
def __init__(self, mqtt, pin):
self.pir = MotionSensor(pin=pin)
self.pir.when_motion = self.motion
# store the mqtt client we'll need to call
self.mqtt = mqtt
# This PIR object is created in the main thread
# so store that loop object
self.loop = asyncio.get_running_loop()
def motion(self):
# motion is called in the gpiozero monitoring thread
# it has to use our stored copy of the loop and then
# tell that loop to call the callback:
self.loop.call_soon_threadsafe(self.mqtt.publish,
f'sensor/gpiod/pir/kitchen', True)
当设置When_motion属性时,gpiozero将创建一个执行回调的新线程(这一点没有很好的文档记录)。如果回调应该在主异步IO循环中执行,那么需要将控制权传递回主线程
这个方法可以帮你做到这一点。本质上,当等待发生时,它将回调添加到主异步IO循环调用的任务列表中
然而