This is an automated email from the ASF dual-hosted git repository.
pandalee pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fury.git
The following commit(s) were added to refs/heads/main by this push:
new d49816cd perf(python): get object __dict__ for faster field read/write
(#2003)
d49816cd is described below
commit d49816cd51d6d9c596cc6f9c18c925b87a788960
Author: Shawn Yang <[email protected]>
AuthorDate: Sun Jan 12 18:13:11 2025 +0800
perf(python): get object __dict__ for faster field read/write (#2003)
## What does this PR do?
This PR extract `__dict__` in object when serialize a dataclass without
slots for faster attribute set/set by 16%
## Related issues
<!--
Is there any related issue? Please attach here.
- #xxxx0
- #xxxx1
- #xxxx2
-->
## Does this PR introduce any user-facing change?
<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fury/issues/new/choose) describing the
need to do so and update the document if necessary.
-->
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
For following object:
```python
COMPLEX_OBJECT = ComplexObject1(
f1=ComplexObject2(f1=True, f2={-1: 2}),
f2="abc",
f3=["abc", "abc"],
f4={1: 2},
f5=2**7 - 1,
f6=2**15 - 1,
f7=2**31 - 1,
f8=2**63 - 1,
f9=1.0 / 2,
f10=1 / 3.0,
f12=[-1, 4],
)
```
This PR gives a 16% speed up
---
python/pyfury/serializer.py | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/python/pyfury/serializer.py b/python/pyfury/serializer.py
index 878c456f..f7276f7d 100644
--- a/python/pyfury/serializer.py
+++ b/python/pyfury/serializer.py
@@ -288,6 +288,7 @@ class DataClassSerializer(Serializer):
# This will get superclass type hints too.
self._type_hints = typing.get_type_hints(clz)
self._field_names = sorted(self._type_hints.keys())
+ self._has_slots = hasattr(clz, "__slots__")
# TODO compute hash
self._hash = len(self._field_names)
self._generated_write_method = self._gen_write_method()
@@ -300,16 +301,21 @@ class DataClassSerializer(Serializer):
def _gen_write_method(self):
context = {}
counter = itertools.count(0)
- buffer, fury, value = "buffer", "fury", "value"
+ buffer, fury, value, value_dict = "buffer", "fury", "value",
"value_dict"
context[fury] = self.fury
stmts = [
f'"""write method for {self.type_}"""',
f"{buffer}.write_int32({self._hash})",
]
+ if not self._has_slots:
+ stmts.append(f"{value_dict} = {value}.__dict__")
for field_name in self._field_names:
field_type = self._type_hints[field_name]
field_value = f"field_value{next(counter)}"
- stmts.append(f"{field_value} = {value}.{field_name}")
+ if not self._has_slots:
+ stmts.append(f"{field_value} = {value_dict}['{field_name}']")
+ else:
+ stmts.append(f"{field_value} = {value}.{field_name}")
if field_type is bool:
stmts.extend(gen_write_nullable_basic_stmts(buffer,
field_value, bool))
elif field_type == int:
@@ -332,7 +338,13 @@ class DataClassSerializer(Serializer):
def _gen_read_method(self):
context = dict(_jit_context)
- buffer, fury, obj_class, obj = "buffer", "fury", "obj_class", "obj"
+ buffer, fury, obj_class, obj, obj_dict = (
+ "buffer",
+ "fury",
+ "obj_class",
+ "obj",
+ "obj_dict",
+ )
ref_resolver = "ref_resolver"
context[fury] = self.fury
context[obj_class] = self.type_
@@ -346,9 +358,14 @@ class DataClassSerializer(Serializer):
f""" raise ClassNotCompatibleError(
"Hash read_hash is not consistent with {self._hash} for
{self.type_}")""",
]
+ if not self._has_slots:
+ stmts.append(f"{obj_dict} = {obj}.__dict__")
def set_action(value: str):
- return f"{obj}.{field_name} = {value}"
+ if not self._has_slots:
+ return f"{obj_dict}['{field_name}'] = {value}"
+ else:
+ return f"{obj}.{field_name} = {value}"
for field_name in self._field_names:
field_type = self._type_hints[field_name]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]