函数分类
在Home Assistant中,一项工作由一个将被调用的函数表示。它将在我们的事件循环或线程池中运行,具体取决于它是否是异步安全的。
Home Assistant使用的约定是,所有必须在事件循环内运行的函数都以 async_
为前缀。
协程函数
协程是基于Python生成器语法的特殊函数,允许它们在等待结果时暂停执行。
调用协程函数将返回一个生成器对象,但实际上不会开始执行。这个对象将在从另一个协程中 yield
出来或者被调度到事件循环中时执行任务。
要声明一个函数为协程,从 asyncio
包中导入协程注释并注释你的函数。
import asyncio
@asyncio.coroutine
def async_look_my_coroutine(target):
result = yield from entity.async_turn_on()
if result:
print("hello {}".format(target))
hass.loop.create_task(async_look_my_coroutine("world"))
在这个例子中,我们通过调用 hass.loop.create_task
来调度协程。这将把协程添加到要运行的任务队列中。当事件循环运行 async_look_my_coroutine
时,当调用 yield from entity.async_turn_on()
时,它将暂停任务。此时,将调度一个新任务来执行 entity.async_turn_on()
。当那个任务执行完成后,async_look_my_coroutine
将恢复执行。
回调函数
这是一个普通函数,被认为可以在事件循环内安全运行。回调函数不能暂停自己,因此不能进行任何I/O操作或调用协程。回调函数可以调度一个新任务,但不能等待结果。
要声明一个函数为回调函数,从核心包中导入回调注释并注释你的函数。
在Home Assistant中,回调函数的一个常见用例是作为事件或服务调用的监听器。它可以处理传入的信息,然后调度正确的调用。以下是来自自动化组件的示例。
from homeassistant.core import callback
@callback
def async_trigger_service_handler(service_call):
"""处理自动化触发服务调用。"""
vars = service_call.data.get(ATTR_VARIABLES)
for entity in component.async_extract_from_service(service_call):
hass.loop.create_task(entity.async_trigger(vars, True))
在这个例子中,entity.async_trigger
是一个协程函数。调用协程函数将返回一个协程任务。传入的参数将在任务执行时使用。
要执行任务,我们必须将其调度到事件循环上执行。这是通过调用 hass.loop.create_task
来完成的。
为什么要有回调函数?
你可能会想,如果协程可以做回调函数能做的所有事情,为什么还要有回调函数呢?原因是性能和核心API对象更好的状态一致性。
当协程A等待协程B时,它将暂停自己并调度一个新任务来运行B。这意味着事件循环现在正在运行A、B,然后再运行A。如果B是一个回调函数,A将永远不必暂停自己,因此事件循环只是在运行A。一致性的含义是,排队在事件循环上运行的其他事件将继续等待,直到回调函数完成,但在让步给另一个协程时会交错执行。
事件循环和线程安全
这些函数在线程和事件循环中都可以安全运行。这些函数通常执行计算或在内存中转换数据。任何进行I/O操作的函数都不属于这个类别。许多标准库函数属于这个类别。例如,使用 sum
计算一组数字的总和或合并两个字典。
没有特殊的注释来标记函数属于这个类别,在从事件循环内部使用这些函数时应该小心。如果有疑问,查看它们的实现。
其他函数
这些是所有不属于前面类别的函数。这些函数要么是线程安全的,要么不被认为可以在事件循环内安全运行。这些是使用 sleep
或执行I/O操作的函数。
不需要特殊注释就被认为属于这个类别。
总结
本文主要介绍了Home Assistant中函数的分类,包括协程函数、回调函数、事件循环和线程安全函数以及其他函数。协程函数基于Python生成器语法,可暂停执行等待结果,需用 asyncio.coroutine
注释;回调函数普通且安全,可处理信息和调度任务,用 callback
注释;事件循环和线程安全函数可在线程和事件循环中安全运行,多为计算或数据转换类,无特殊注释;其他函数不属于上述类别,如使用 sleep
或执行I/O操作的函数,也无特殊注释。同时解释了回调函数存在的原因是性能和状态一致性考虑。在使用各类函数时需注意其特性和适用场景。