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

4.x: Make plain Empty<T>() a singleton. #544

Merged
merged 4 commits into from
May 29, 2018

Conversation

akarnokd
Copy link
Collaborator

@akarnokd akarnokd commented May 28, 2018

This PR changes the no-argument Empty<T> operator into a singleton. There is practically no state to this operator and the current implementation schedules work on the ImmediateScheduler, which is almost no-op (the delegate that signals onCompleted gets executed immediately and there is a throwaway AsyncLockScheduler as well).

The instantiation overhead inside the Producer<TTarget> may be avoided as well but currently the type serves as the indicator for trusted source and safeguards are not placed. A plain IObservable implementation fails 2 unit tests because the applied safeguards consume a thrown exception instead of letting it bubble up.

Update:

I've also changed the scheduled version to use the Schedule<TState>(TState, Func<...>) method to avoid allocating a delegate due to capture of this.

@@ -28,13 +29,27 @@ public _(IObserver<TResult> observer, IDisposable cancel)

public IDisposable Run(IScheduler scheduler)
{
return scheduler.Schedule(Invoke);
return scheduler.Schedule(this, Invoke);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will unfortunately due to this not save the allocation of a delegate, if you make it an anonymous lambda, it will.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I should make the body of Invoke a lambda here? I'll update the PR shortly.

Also a phylosophical question: why do I have to fight the optimizer so much?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean, why doesn't Roslyn cache the delegate for a static method?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Lambdas aren't new so I'd expect compiler optimizations already present for them.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For lambdas, sure, there are and always were. But 'Invoke' is a method group, not a lambda. It's probably easy to implement but breaking.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may as well just leave it like that, Roslyn will eventually catch up I guess and then it's free lunch.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who knows how long 4.1 will stick with people. Let's have as many optimizations now without waiting for compiler support.

@danielcweber danielcweber merged commit 6c456b7 into dotnet:master May 29, 2018
@akarnokd akarnokd deleted the SingletonEmpty branch May 30, 2018 13:01
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