Replace Linear-time .children Comprehensions with Data Structure tracking Parent-Child relationships each time they change
Currently, a number of "children" properties accessible through the Python API incur linear (in bpy objs, collections, scenes, etc, depending on specific case) run-time cost. The most notable example of this is probably the
.children
property of
bpy_types.Object
, which in a recent Blender version was implemented like:
@property
def children(self):
"""All the children of this object.
.. note:: Takes ``O(len(bpy.data.objects))`` time."""
import bpy
return tuple(child for child in bpy.data.objects
if child.parent == self)
github.com/blender/blender/blob/b73dc36859e03845f702a3e985b536ac9afef63a/release/scripts/modules/bpy_types.py
(many operations defined in
bpy_types
behave like this, e.g.
users_dupli_group
for
Collection
;
users_collection
,
users_scene
for
Object
; and
children
for
_GenericBone
. An important case where I was not able to determine the behavior due to my ignorance of Blender's C source is
Collection
's
.children
property)
When writing
Add On
s that create/manipulate/inspect the children of large numbers of objects, this linear cost can be prohibitive (in a small-scale test I'm currently working on, the generators associated with
.children
accounted for 30 of 60 secs of run-time, according to cProfile output, and this would likely get much worse in large-scale tests). It is I think always possible to work around this, currently, by avoiding the built-in
.children
property and instead tracking parent-child relationships explicitly in a custom
Add On
-defined Python dictionary, but this seems somewhat cumbersome, more error-prone, and maybe less performant than native support for directly tracking changes in parent-child relationships would be. The current behavior is also somewhat counterintuitive, and requires careful profiling to identify as a problem during
Add On
development.
I may be missing a reason the proposed change is more difficult or expensive to do than I imagine (indeed, partially beginning this submission hoping that someone will explain to me if there is a good reason for the current design pattern), but it seems to me that maintaining an explicit data structure associated with each object that caches references to its parent and children (and to its
users_collections
, etc, depending on which
property
look-up is being made more efficient) and updates these whenever an object is created, removed, or a parenting/unparenting operation is performed would almost always be at least as performant as the current approach, and would be orders of magnitude more efficient when very large numbers of look-ups over large numbers of objects of the pertinent type are required.
0 Comments