perf(http-client-python): precompute model class state to speed up list operations#10475
Draft
l0lawrence wants to merge 1 commit intomicrosoft:mainfrom
Draft
perf(http-client-python): precompute model class state to speed up list operations#10475l0lawrence wants to merge 1 commit intomicrosoft:mainfrom
l0lawrence wants to merge 1 commit intomicrosoft:mainfrom
Conversation
…st operations Profiling azure-storage-blob's list_blobs against a 500-blob container showed the TypeSpec runtime deserializer as the dominant hot path: - Model.__init__ rebuilt a defaults dict per instance - _RestField._rest_name was a @Property called once per field per model (73,024 calls for 500 blobs) - Model._calculated used a string set + membership test per subclass - _deserialize_default swallowed all exceptions, masking real bugs This change: * Precomputes cls._defaults once in Model.__new__ * Promotes _rest_name from property to plain attribute set in __new__ * Replaces the _calculated string set with a cls._calculated_done bool (checked via __dict__.get so subclasses don't inherit the flag) * Narrows except Exception to except DeserializationError in _deserialize_default (safe - _deserialize_with_callable already wraps) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
commit: |
Contributor
|
All changed packages have been documented.
Show changes
|
Collaborator
|
You can try these changes here
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Profiling
azure-storage-blob'slist_blobsagainst a 500-blob container on the in-progress TypeSpec migration (Azure/azure-sdk-for-python#45133) identified the generated_utils/model_base.pydeserializer as the dominant hot path – roughly half the wall time was spent there, causing a ~-48% throughput regression vs. the current msrest-generated package. Download/upload were unaffected because they deserialize exactly one model per HTTP call regardless of payload size;list_blobsis the only operation where one response produces N model instances, so per-instance overhead is what matters.This PR addresses the most mechanical of those hot spots in the shared
model_base.py.jinja2template so every TypeSpec-emitted Python SDK benefits.Changes
cls._defaultsonce inModel.__new__–Model.__init__no longer walks_attr_to_rest_fieldon every instance build; it just copies the pre-built mapping._RestField._rest_namefrom@propertyto plain attribute – set once in__new__; removes a descriptor lookup that was hit once per field per model (~73k calls for a 500-blob list)._calculatedset with a_calculated_done: boolflag – checked viacls.__dict__.get("_calculated_done", False)so subclasses re-run the per-class setup correctly without inheriting the flag._deserialize_default'sexcept Exceptiontoexcept DeserializationError– the caller_deserialize_with_callablealready wraps everything intoDeserializationError, so this is semantically equivalent for the success-and-expected-failure paths while surfacing real coding bugs (AttributeError/TypeError) instead of masking them as deserialization failures.No public API change; no generated-code change for consumers beyond the
_utils/model_base.pybody itself.Validation
npm run build– clean.npm run regenerate– unbranded fixtures regenerate successfully. Regenerated_utils/model_base.pycontains the new code paths (_calculated_done,_defaults =,except DeserializationError).tests/unit/test_model_base_serialization.py+test_model_base_xml_serialization.py– 156/157 pass. The one failure (test_null_serialization) is a pre-existing cross-packageisinstancemismatch (azure.core.serialization._Nullvs.corehttp.serialization._Null) in the unchanged_deserialize_with_callabledispatcher and is unrelated to this change – it reproduces onmainwhen bothazure.coreandcorehttpare importable simultaneously in the test env.Follow-ups (not in this PR)
There are larger wins still on the table that I'd like to address in a second PR if this one is well-received:
_init_from_xmlstops recomputing it once per field per instance.typing.get_args/ annotation analysis in_deserializethat currently re-runs for every instance._deserialize_with_callabledispatcher into a precomputed callable per field.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com