From 4bc28489c509b63e829f8120f1b68ff902950db5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 19 Feb 2024 03:28:50 -0600 Subject: [PATCH] Improve performance of waiting for after dependencies and device config entries (#110902) To wait for after dependencies we created a task to wait an asyncio.Event object, instead of using an Event we can use an asyncio.Future instead and avoid the need for a task wrapper --- homeassistant/config_entries.py | 4 ++-- homeassistant/setup.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index e5f8d20578a..1126defcda3 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -1741,8 +1741,8 @@ class ConfigEntries: Config entries which are created after Home Assistant is started can't be waited for, the function will just return if the config entry is loaded or not. """ - if setup_event := self.hass.data.get(DATA_SETUP_DONE, {}).get(entry.domain): - await setup_event.wait() + if setup_future := self.hass.data.get(DATA_SETUP_DONE, {}).get(entry.domain): + await setup_future # The component was not loaded. if entry.domain not in self.hass.config.components: return False diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 80dd95aa17b..1886fefe182 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -43,7 +43,7 @@ BASE_PLATFORMS = {platform.value for platform in Platform} # the task returned True. DATA_SETUP = "setup_tasks" -# DATA_SETUP_DONE is a dict [str, asyncio.Event], indicating components which +# DATA_SETUP_DONE is a dict [str, asyncio.Future], indicating components which # will be setup: # - Events are added to DATA_SETUP_DONE during bootstrap by # async_set_domains_to_be_loaded, the key is the domain which will be loaded. @@ -117,7 +117,9 @@ def async_set_domains_to_be_loaded(hass: core.HomeAssistant, domains: set[str]) - Keep track of domains which will load but have not yet finished loading """ hass.data.setdefault(DATA_SETUP_DONE, {}) - hass.data[DATA_SETUP_DONE].update({domain: asyncio.Event() for domain in domains}) + hass.data[DATA_SETUP_DONE].update( + {domain: hass.loop.create_future() for domain in domains} + ) def setup_component(hass: core.HomeAssistant, domain: str, config: ConfigType) -> bool: @@ -155,8 +157,8 @@ async def async_setup_component( future.set_exception(err) raise finally: - if domain in hass.data.get(DATA_SETUP_DONE, {}): - hass.data[DATA_SETUP_DONE].pop(domain).set() + if future := hass.data.get(DATA_SETUP_DONE, {}).pop(domain, None): + future.set_result(None) async def _async_process_dependencies( @@ -172,17 +174,15 @@ async def _async_process_dependencies( if dep not in hass.config.components } - after_dependencies_tasks = {} - to_be_loaded = hass.data.get(DATA_SETUP_DONE, {}) + after_dependencies_tasks: dict[str, asyncio.Future[None]] = {} + to_be_loaded: dict[str, asyncio.Future[None]] = hass.data.get(DATA_SETUP_DONE, {}) for dep in integration.after_dependencies: if ( dep not in dependencies_tasks and dep in to_be_loaded and dep not in hass.config.components ): - after_dependencies_tasks[dep] = hass.loop.create_task( - to_be_loaded[dep].wait() - ) + after_dependencies_tasks[dep] = to_be_loaded[dep] if not dependencies_tasks and not after_dependencies_tasks: return []