Speed up setting up event trackers (#93823)

noticed in https://github.com/home-assistant/core/pull/93601 that
the cost of creating the function in the closure was a bit expensive
since we do it once per entity
This commit is contained in:
J. Nick Koston 2023-05-30 19:12:52 -05:00 committed by GitHub
parent 9f0d3bfce8
commit 3186ddb095
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -312,6 +312,25 @@ def _remove_empty_listener() -> None:
"""Remove a listener that does nothing."""
@callback
def _remove_listener(
hass: HomeAssistant,
listeners_key: str,
keys: list[str],
job: HassJob[[Event], Any],
callbacks: dict[str, list[HassJob[[Event], Any]]],
) -> None:
"""Remove listener."""
for key in keys:
callbacks[key].remove(job)
if len(callbacks[key]) == 0:
del callbacks[key]
if not callbacks:
hass.data[listeners_key]()
del hass.data[listeners_key]
def _async_track_event(
hass: HomeAssistant,
keys: str | Iterable[str],
@ -333,12 +352,16 @@ def _async_track_event(
if isinstance(keys, str):
keys = [keys]
callbacks: dict[str, list[HassJob[[Event], Any]]] = hass.data.setdefault(
callbacks_key, {}
)
hass_data = hass.data
if listeners_key not in hass.data:
hass.data[listeners_key] = hass.bus.async_listen(
callbacks: dict[str, list[HassJob[[Event], Any]]] | None = hass_data.get(
callbacks_key
)
if not callbacks:
callbacks = hass_data[callbacks_key] = {}
if listeners_key not in hass_data:
hass_data[listeners_key] = hass.bus.async_listen(
event_type,
callback(ft.partial(dispatcher_callable, hass, callbacks)),
event_filter=callback(ft.partial(filter_callable, hass, callbacks)),
@ -347,21 +370,13 @@ def _async_track_event(
job = HassJob(action, f"track {event_type} event {keys}")
for key in keys:
callbacks.setdefault(key, []).append(job)
callback_list = callbacks.get(key)
if callback_list:
callback_list.append(job)
else:
callbacks[key] = [job]
@callback
def remove_listener() -> None:
"""Remove listener."""
for key in keys:
callbacks[key].remove(job)
if len(callbacks[key]) == 0:
del callbacks[key]
if not callbacks:
hass.data[listeners_key]()
del hass.data[listeners_key]
return remove_listener
return ft.partial(_remove_listener, hass, listeners_key, keys, job, callbacks)
@callback