Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

anytrait: evaluate performance consequences of using per-trait listeners instead of per-object listeners #1502

Open
mdickinson opened this issue Sep 6, 2021 · 2 comments
Labels
topic: traits listener rework Issues related to reworking listener infrastructure; see also EEP2, EEP3 type: performance Issues related to speed or memory usage
Milestone

Comments

@mdickinson
Copy link
Member

The filtered trait mechanisms in the observe framework (and in particular the anytrait special case introduced in #1496) register listeners on a per-trait basis.

This is in contrast to the on_trait_change "anytrait" handling, which registers listeners on a per-object basis.

It would be worth analysing the consequences of this choice on performance and deciding whether there's a performance case for looking at migrating the filtered trait observers to use the object-based notification.

@mdickinson mdickinson added topic: traits listener rework Issues related to reworking listener infrastructure; see also EEP2, EEP3 type: performance Issues related to speed or memory usage labels Sep 6, 2021
@mdickinson
Copy link
Member Author

mdickinson commented Sep 6, 2021

Hmm. The on_trait_change behaviour is less clear cut than I thought:

For example, after:

from traits.api import HasTraits, Int, Str


def print_event(obj, name, old, new):
    print(obj, name, old, new)


class A(HasTraits):
    foo = Int()

    bar = Str()


a = A()
a.on_trait_change(print_event, "anytrait")

We have:

>>> a._notifiers(False)
[<traits.trait_notifiers.TraitChangeNotifyWrapper object at 0x10d4b6d90>]
>>> a._notifiers(False)[0].handler  # double check that the handler is what we think it is
<function print_event at 0x10d40f0d0>
>>> a.trait("foo")._notifiers(False)

So we've registered an object-level handler for a, but no trait-level handlers.

But if instead we do this:

>>> a.on_trait_change(print_event, "+")

Then we register on a per-trait basis instead of a per-object basis:

>>> a._notifiers(False)
>>> a.trait("foo")._notifiers(False)
[<traits.trait_notifiers.TraitChangeNotifyWrapper object at 0x10d983f10>]
>>> a.trait("bar")._notifiers(False)
[<traits.trait_notifiers.TraitChangeNotifyWrapper object at 0x10d983f40>]

The _anytrait_changed handler also appears to register on a per-trait basis rather than a per-object basis.

@mdickinson
Copy link
Member Author

Not for this release.

@mdickinson mdickinson added this to the 7.0.0 release milestone Sep 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: traits listener rework Issues related to reworking listener infrastructure; see also EEP2, EEP3 type: performance Issues related to speed or memory usage
Projects
None yet
Development

No branches or pull requests

1 participant