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

Interleave tasks in FindAllPagesAsync #26

Closed
sliekens opened this issue Oct 24, 2015 · 0 comments
Closed

Interleave tasks in FindAllPagesAsync #26

sliekens opened this issue Oct 24, 2015 · 0 comments
Assignees
Milestone

Comments

@sliekens
Copy link
Collaborator

The FindAllPagesAsync extension method returns a collection of tasks that complete in order that they were started.

public static IEnumerable<Task<ICollectionPage<T>>> FindAllPagesAsync<T>(this IPaginator<T> instance, int pageSize, int pageCount, CancellationToken cancellationToken)

Instead, the tasks should be interleaved so that tasks are returned in their order of completion, using this task combinator. It is a small change that dramatically improves performance by minimizing idle CPU time between incomplete requests.

https://msdn.microsoft.com/en-us/library/hh873173(v=vs.110).aspx

static IEnumerable<Task<T>> Interleaved<T>(IEnumerable<Task<T>> tasks)
{
    var inputTasks = tasks.ToList();
    var sources = (from _ in Enumerable.Range(0, inputTasks.Count) 
                   select new TaskCompletionSource<T>()).ToList();
    int nextTaskIndex = -1;
    foreach (var inputTask in inputTasks)
    {
        inputTask.ContinueWith(completed =>
        {
            var source = sources[Interlocked.Increment(ref nextTaskIndex)];
            if (completed.IsFaulted) 
                source.TrySetException(completed.Exception.InnerExceptions);
            else if (completed.IsCanceled) 
                source.TrySetCanceled();
            else 
                source.TrySetResult(completed.Result);
        }, CancellationToken.None, 
           TaskContinuationOptions.ExecuteSynchronously, 
           TaskScheduler.Default);
    }
    return from source in sources 
           select source.Task;
}

There is also a synchronous method named FindAllPages that returns a collection of Lazy<TResult> instead of Task<TResult>. Because it is synchronous, I don't think that it can be interleaved in this way. Any method that interleaves Lazy objects would probably still use TaskCompletionSource under the hood, defeating the purpose of synchronous methods. One more reason to drop synchronous API calls.

@sliekens sliekens added this to the v1.4.0 milestone Oct 24, 2015
@sliekens sliekens self-assigned this Oct 24, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant