Skip to content

Use binary search when subscribeing #4138

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

bicarlsen
Copy link
Contributor

Use binary search when subscribeing to a SubscriberSet. In tests, reduced subscribe time by 7 to 10 times.

Use binary search when `subscribe`ing to a `SubscriberSet`. In tests, reduced `subscribe` time by 7 to 10 times.
@bicarlsen
Copy link
Contributor Author

In unsubscribe there is a note saying not to use swap_remove because it may mess up the order which is important for nested effects. So sorting the subscription Vec may break this, too, in which case this PR should be rejected.

@bicarlsen
Copy link
Contributor Author

bicarlsen commented Jul 11, 2025

If order matters, another option would be to assume that recently created subscribers are more likely to be added again than older ones, so to run the search from the tail -- e.g. with self.0.iter().rev().rposition(|s| s == &subscriber).is_none(). In my tests this gave a small but noticable speed up.

@gbj
Copy link
Collaborator

gbj commented Jul 20, 2025

Yes, the order does matter and should follow insertion order.

I think the trade-off here is between whether a data type like FxIndexSet (i.e., rustc_hash + indexmap) is a better type to use rather than Vec<_>. (IndexSet, unlike HashSet, would maintain the insertion order when iterating, which is important to ensure notifications happen in the same order that subscriptions happened.)

Pros of Vec

  • Smaller binary size
  • Below a certain number of subscribers n, lookup in the Vec<_> will be faster (but both will be very fast)

Pros of IndexSet

  • Above a certain number of subscribers n, lookup in the IndexSet will be faster (it is O(1), whereas the Vec is obviously O(n))

To be clear I don't know what the size n is, and I have not (recently) tested the release-mode binary-size impact. If it's minimal I'd be open to a change in that direction.

@bicarlsen
Copy link
Contributor Author

An option could be to implement a HashSignal (or a better name) that uses IndexSet under the hood. This way people explicitly opt in to it to test it out and we could gather real-world feedback on its performance. Perhaps it could put it behind a feature flag, too.

Not sure how to test the binary size impact, but if you give me some guidance, I'd be happy to test it and get an initial feel.

Perhaps it's best to reject this PR and open an issue related to the change instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants