[英]Call async method from sync callback in Python
以下 python 脚本使用来自 Ruuvi 标签的读取温度。 在同步 Ruuvi 回调中,我们要调用一个异步方法 (send_message_to_output)。 以下代码将在第二次调用时引发异常
运行时错误:事件循环已关闭
如何让 handle_data 多次工作?
import asyncio
from azure.iot.device.aio import IoTHubModuleClient
from ruuvitag_sensor.ruuvi import RuuviTagSensor
async def main():
device_client = IoTHubModuleClient.create_from_edge_environment()
await device_client.connect()
def handle_data(found_data):
asyncio.get_event_loop().run_until_complete(device_client.send_message_to_output("some data", "ruuvi"))
while True:
RuuviTagSensor.get_datas(handle_data)
time.sleep(5)
await device_client.disconnect()
if __name__ == "__main__":
asyncio.run(main())
根据您的例外情况,循环似乎由于某种原因而关闭。 我认为这是由于handle_data
函数中的run_until_complete
导致关闭循环的反应。
因此,我建议尝试以下方法:
import asyncio
from azure.iot.device.aio import IoTHubModuleClient
from ruuvitag_sensor.ruuvi import RuuviTagSensor
async def main(main_loop):
tasks = list()
device_client = IoTHubModuleClient.create_from_edge_environment()
await device_client.connect()
def handle_data(found_data):
nonlocal main_loop
nonlocal tasks
tasks.append(main_loop.create_task(device_client.send_message_to_output("some data", "ruuvi")))
while True:
RuuviTagSensor.get_datas(handle_data)
# We need to wait async in order to let the tasks run
await asyncio.sleep(5)
# This is just an insurance that all the tasks (messages to output) completed
await asyncio.wait(tasks, timeout=5)
await device_client.disconnect()
if __name__ == "__main__":
# Creating and closing the loop here
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop)
loop.close()
替代(更复杂)的解决方案可以使用从队列中读取并调用send_message_to_output
函数的函数:
import asyncio
from azure.iot.device.aio import IoTHubModuleClient
from ruuvitag_sensor.ruuvi import RuuviTagSensor
async def main(main_loop):
q = asyncio.Queue()
stopping = asyncio.Event()
device_client = IoTHubModuleClient.create_from_edge_environment()
await device_client.connect()
async def send_msg():
nonlocal q
nonlocal stopping
nonlocal device_client
while not stopping.is_set():
msg, sender = await q.get()
if msg is None and sender is None:
break
await device_client.send_message_to_output(msg, sender)
def handle_data(found_data):
nonlocal q
nonlocal stopping
if stopping.is_set():
return
q.put_nowait(("some data", "ruuvi"))
while True:
RuuviTagSensor.get_datas(handle_data)
await asyncio.sleep(5)
send_msg_task = main_loop.create_task(send_msg())
await q.put((None, None))
await stopping.set()
await send_msg_task
await device_client.disconnect()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop)
loop.close()
这里的想法是将handle_data
与send_msg
。 通过这种方式,我设法使send_msg
成为一个异步函数,现在不需要创建loop
或Task
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.