使用异步
尽管我们有一个向后兼容的 API,但直接使用异步核心会快得多。大多数核心组件已经被重写以利用异步核心。这包括 EntityComponent 助手(光线、开关等的基础)、脚本、组和自动化。
与核心的交 互
Home Assistant 核心中的所有方法都有两种版本:异步版本和可以从其他线程调用的版本。其他线程的版本只是以线程安全的方式调用异步版本的包装器。
因此,如果你在回调或协程中从核心(hass 对象)进行调用,请使用以 async_ 开头的方法。如果你需要调用一个 async_ 函数,该函数是一个协程,你的任务也必须是一个协程。
实现一个异步组件
要使组件异步,需实现 async_setup。
def setup(hass, config):
"""设置组件。"""
# 在事件循环外部设置组件的代码。
将变成:
async def async_setup(hass, config):
"""设置组件。"""
# 在事件循环内部设置组件的代码。
实现一个异步平台
对于我们支持异步设置的平台,需要使用协程 async_setup_platform,而不是 setup_platform。
def setup_platform(hass, config, add_entities, discovery_info=None):
"""设置平台。"""
# 在事件循环外部设置平台的代码。
将变成:
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""设置平台。"""
# 在事件循环内部设置平台的代码。
与原始参数的唯一区别是 add_entities
函数已被异步友好的回调 async_add_entities
替换。
实现一个异步实体
通过将更新方法转换为异步,你可以使实体支持异步。这要求你的实体的依赖项也必须是异步友好的!
class MyEntity(Entity):
def update(self):
"""检索最新状态。"""
self._state = fetch_state()
将变成:
class MyEntity(Entity):
async def async_update(self):
"""检索最新状态。"""
self._state = await async_fetch_state()
确保在实体上定义的所有属性不会导致 I/O 操作。所有数据都必须在更新方法内部获取并缓存到实体中。这是因为这些属性是在事件循环内读取的,因此执行 I/O 会导致 Home Assistant 的核心等待直到你的 I/O 完成。
从线程调用异步函数
有时你可能在一个线程中,并且想调用一个仅以异步形式可用的函数。Home Assistant 包含一些异步帮助工具来帮助实现这一点。
在以下示例中,say_hello
将调度 async_say_hello
并阻塞,直到该函数执行完毕并返回结果。
import asyncio
def say_hello(hass, target):
return asyncio.run_coroutine_threadsafe(
async_say_hello(hass, target), hass.loop
).result()
async def async_say_hello(hass, target):
return f"你好 {target}!"
警告: 请小心!如果异步函数使用执行器作业,可能会导致死锁。
从异步调用同步函数
如果你在异步上下文中运行,有时可能需要调用同步函数。这样做:
# hub.update() 是一个同步函数。
result = await hass.async_add_executor_job(hub.update)
从异步启动独立任务
如果你想生成一个不会阻塞当前异步上下文的任务,可以选择在事件循环上将其创建为任务。这样它将并行执行。
hass.async_create_task(async_say_hello(hass, target))