← All ideas
  • Published 4 Jul 2021

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%

Development Status: Open

Upvote 0 Downvote 0
neverconvex
4 Jul 2021

0 Comments