Ordering tasks by completion time by tracking their index in the argument list?

I recently asked a question about the possibility of cleaning some code, the code had to wait until everyone Taskin List<Task<T>>, but canceled all Taskif you returned a value of false.

A user named Servy quickly created a method that eloquently orders List<Task<T>>by the time they are completed. After reading the answer a bit, I think / thought I understand / there was a method. Then I went to use the method, but quickly realized the problem. I need to be recognized Taskas they are completed. But the method Orderproposed by Servy does not provide any means for this (because I can not compare the continuation of the task returned Order, in mine List<Task<>>, I put it initially).

So, I went to change the method to return Tuple<T, int>where it intrepresents the source index Taskin the arguments provided.

public static IEnumerable<Task<Tuple<T, int>>> OrderByCompletion<T>(IEnumerable<Task<T>> tasks)
{
    var taskList = tasks.ToList();
    var taskSources = new BlockingCollection<TaskCompletionSource<Tuple<T, int>>>();
    var taskSourceList = new List<TaskCompletionSource<Tuple<T, int>>>(taskList.Count);

    for (int i = 0; i < taskList.Count; i++)
    {
        var task = taskList[i];
        var newSource = new TaskCompletionSource<Tuple<T, int>>();
        taskSources.Add(newSource);
        taskSourceList.Add(newSource);

        task.ContinueWith(t =>
        {
            var source = taskSources.Take();

            if (t.IsCanceled)
                source.TrySetCanceled();
            else if (t.IsFaulted)
                source.TrySetException(t.Exception.InnerExceptions);
            else if (t.IsCompleted)
                source.TrySetResult(new Tuple<T, int>(t.Result, i));
        }, CancellationToken.None, TaskContinuationOptions.PreferFairness, TaskScheduler.Default);
    }

    return taskSourceList.Select(tcs => tcs.Task);
}

// Usage
foreach(var task in myTaskList.OrderByCompletion())
    Tuple<Boolean, int> result = await task;

, , , Tuple Count List<Task<>>, OrderByCompletion .

, , , , .

- ?

0
1

, i Action<>.

, Action, , i taskList.Count ( for).

, for:

for (int i = 0; i < taskList.Count; i++)
{
    var task = taskList[i];
    var newSource = new TaskCompletionSource<Tuple<T, int>>();
    taskSources.Add(newSource);
    taskSourceList.Add(newSource);

    int index = i; // <- add this variable.

    task.ContinueWith(t =>
    {
        var source = taskSources.Take();

        if (t.IsCanceled)
            source.TrySetCanceled();
        else if (t.IsFaulted)
            source.TrySetException(t.Exception.InnerExceptions);
        else if (t.IsCompleted)
            source.TrySetResult(new Tuple<T, int>(t.Result, index));
    }, CancellationToken.None, TaskContinuationOptions.PreferFairness, TaskScheduler.Default);
}

/ .

+2

Source: https://habr.com/ru/post/1657671/


All Articles