瀏覽代碼

Perf improvements (part 1) (#2779)

* types: remove runtime imports from `is_generic_alias`

Reduce try/except contexts for better performance.

* _decode_var optimizations:

* compile the regex once at module scope
* fast path string scan for REFLEX_VAR_OPENING_TAG before doing more complex logic

* Avoid repeated `hasattr` check in `is_union`

`is_union` gets called a lot, and the hasattr check can be resolved at import
time for better performance.
Masen Furer 1 年之前
父節點
當前提交
03aa28320a
共有 2 個文件被更改,包括 34 次插入26 次删除
  1. 22 21
      reflex/utils/types.py
  2. 12 5
      reflex/vars.py

+ 22 - 21
reflex/utils/types.py

@@ -30,6 +30,26 @@ from reflex import constants
 from reflex.base import Base
 from reflex.base import Base
 from reflex.utils import serializers
 from reflex.utils import serializers
 
 
+# Potential GenericAlias types for isinstance checks.
+GenericAliasTypes = [_GenericAlias]
+
+with contextlib.suppress(ImportError):
+    # For newer versions of Python.
+    from types import GenericAlias  # type: ignore
+
+    GenericAliasTypes.append(GenericAlias)
+
+with contextlib.suppress(ImportError):
+    # For older versions of Python.
+    from typing import _SpecialGenericAlias  # type: ignore
+
+    GenericAliasTypes.append(_SpecialGenericAlias)
+
+GenericAliasTypes = tuple(GenericAliasTypes)
+
+# Potential Union types for isinstance checks (UnionType added in py3.10).
+UnionTypes = (Union, types.UnionType) if hasattr(types, "UnionType") else (Union,)
+
 # Union of generic types.
 # Union of generic types.
 GenericType = Union[Type, _GenericAlias]
 GenericType = Union[Type, _GenericAlias]
 
 
@@ -75,22 +95,7 @@ def is_generic_alias(cls: GenericType) -> bool:
     Returns:
     Returns:
         Whether the class is a generic alias.
         Whether the class is a generic alias.
     """
     """
-    # For older versions of Python.
-    if isinstance(cls, _GenericAlias):
-        return True
-
-    with contextlib.suppress(ImportError):
-        from typing import _SpecialGenericAlias  # type: ignore
-
-        if isinstance(cls, _SpecialGenericAlias):
-            return True
-    # For newer versions of Python.
-    try:
-        from types import GenericAlias  # type: ignore
-
-        return isinstance(cls, GenericAlias)
-    except ImportError:
-        return False
+    return isinstance(cls, GenericAliasTypes)
 
 
 
 
 def is_union(cls: GenericType) -> bool:
 def is_union(cls: GenericType) -> bool:
@@ -102,11 +107,7 @@ def is_union(cls: GenericType) -> bool:
     Returns:
     Returns:
         Whether the class is a Union.
         Whether the class is a Union.
     """
     """
-    # UnionType added in py3.10
-    if not hasattr(types, "UnionType"):
-        return get_origin(cls) is Union
-
-    return get_origin(cls) in [Union, types.UnionType]
+    return get_origin(cls) in UnionTypes
 
 
 
 
 def is_literal(cls: GenericType) -> bool:
 def is_literal(cls: GenericType) -> bool:

+ 12 - 5
reflex/vars.py

@@ -229,6 +229,13 @@ def _encode_var(value: Var) -> str:
     return str(value)
     return str(value)
 
 
 
 
+# Compile regex for finding reflex var tags.
+_decode_var_pattern_re = (
+    rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
+)
+_decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
+
+
 def _decode_var(value: str) -> tuple[VarData | None, str]:
 def _decode_var(value: str) -> tuple[VarData | None, str]:
     """Decode the state name from a formatted var.
     """Decode the state name from a formatted var.
 
 
@@ -240,6 +247,10 @@ def _decode_var(value: str) -> tuple[VarData | None, str]:
     """
     """
     var_datas = []
     var_datas = []
     if isinstance(value, str):
     if isinstance(value, str):
+        # fast path if there is no encoded VarData
+        if constants.REFLEX_VAR_OPENING_TAG not in value:
+            return None, value
+
         offset = 0
         offset = 0
 
 
         # Initialize some methods for reading json.
         # Initialize some methods for reading json.
@@ -251,12 +262,8 @@ def _decode_var(value: str) -> tuple[VarData | None, str]:
             except json.decoder.JSONDecodeError:
             except json.decoder.JSONDecodeError:
                 return var_data_config.json_loads(var_data_config.json_loads(f'"{s}"'))
                 return var_data_config.json_loads(var_data_config.json_loads(f'"{s}"'))
 
 
-        # Compile regex for finding reflex var tags.
-        pattern_re = rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
-        pattern = re.compile(pattern_re, flags=re.DOTALL)
-
         # Find all tags.
         # Find all tags.
-        while m := pattern.search(value):
+        while m := _decode_var_pattern.search(value):
             start, end = m.span()
             start, end = m.span()
             value = value[:start] + value[end:]
             value = value[:start] + value[end:]