Skip to content

Conversation

@akarnokd
Copy link
Collaborator

@akarnokd akarnokd commented Jun 15, 2018

This PR modifies the schedule logic of the CurrentThreadScheduler to avoid allocating the queue for the first task on an idle scheduler. If the action schedules further tasks in a reentrant manner, those will get queued up just like now.

Since this scheduler is per thread, there is no need for locks/synchronization as each caller thread will only see its own thread-local structures and it can't cross-post to some other thread.

@akarnokd
Copy link
Collaborator Author

The fast-path could be added to the timed case as well (i.e., sleep before executing the plain action, then trampoline if necessary).

/// <param name="action">Action to be executed.</param>
/// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
/// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception>
public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you pack it into the timed overload for the dueTime == 0 case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Maybe. I'm trying to avoid the time arithmetic overhead.

}
finally
{
SetQueue(null);
Copy link
Collaborator

Choose a reason for hiding this comment

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

If the queue is sufficiently small (maybe < 16 or so), we could think about just clearing the queue instead of recreating one next time.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't know if the current capacity is actually available on this type of queue

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nope, it doesn't work. There is no current capacity to ScheduledQueue and the PriorityQueue shrinks itself when the number of items is 25% of its internal capacity upon remove/dequeue.

@akarnokd akarnokd changed the title 4.x: CurrentThreadScheduler fast path untimed Schedule 4.x: CurrentThreadScheduler fast path Schedule Jun 18, 2018
SetQueue(queue);
if (dueTime > TimeSpan.Zero)
{
ConcurrencyAbstractionLayer.Current.Sleep(dueTime);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why can we omit the normalization of dueTime here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

public void Sleep(TimeSpan timeout) => System.Threading.Thread.Sleep(Normalize(timeout));

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We don't mind if it is negative and Sleep will normalize it anyway.

@danielcweber danielcweber merged commit a18e4da into dotnet:master Jun 19, 2018
@akarnokd akarnokd deleted the CurrentThreadSchedulerFastPath branch June 26, 2018 21:34
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