From 006d8e8730ad43bdace7c37eb58b017d76aaa268 Mon Sep 17 00:00:00 2001 From: Keryn Knight Date: Mon, 16 Aug 2021 11:25:38 +0100 Subject: [PATCH] Fixed #269 - Cache the imported AsyncToSync and SyncToAsync classes on the Local class. On first access, after they're imported the first time, hold a reference to them on the class itself. This nets a small increase in performance by avoiding going through the import machinery on every attribute access of a Local instance. Note that these are bound directly to the Local class rather than testing the instance (self) attributes, as doing so in the simple way would yield a RecursionError due to __getattr__ depending on _get_context_id --- asgiref/local.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/asgiref/local.py b/asgiref/local.py index 4a17052f..956292cf 100644 --- a/asgiref/local.py +++ b/asgiref/local.py @@ -31,6 +31,7 @@ class Local: """ CLEANUP_INTERVAL = 60 # seconds + launch_map_classes = None # cache imported (AsyncToSync, SyncToAsync) on first access. def __init__(self, thread_critical: bool = False) -> None: self._thread_critical = thread_critical @@ -48,7 +49,12 @@ def _get_context_id(self): Get the ID we should use for looking up variables """ # Prevent a circular reference - from .sync import AsyncToSync, SyncToAsync + # Once imported the first time, hold a reference to them on the class. + if not Local.launch_map_classes: + from .sync import AsyncToSync, SyncToAsync + Local.launch_map_classes = (AsyncToSync, SyncToAsync) + else: + AsyncToSync, SyncToAsync = Local.launch_map_classes # First, pull the current task if we can context_id = SyncToAsync.get_current_task()