使用 WhenAll 和 ContinueWith 时任务结果的顺序是什么

What is the order of the task result when using WhenAll and ContinueWith

只想知道使用WhenAll和ContinueWith时任务结果的顺序是怎样的。 这些结果是否保证与任务 ID 的顺序相同?

我写了下面的代码

public static async Task<string> PrintNumber(int number)
{
    return await Task.Delay(number*1000).ContinueWith(_=>
    {
        Console.WriteLine(number);return "TaskId:"+Task.CurrentId+" Result:"+number;
    });
}

public static void Main()
{

    Task.WhenAll(new[]
    {
        PrintNumber(3),
        PrintNumber(2),
        PrintNumber(1),

    }).ContinueWith((antecedent) => 
    { 
        foreach(var a in antecedent.Result)
        {
            Console.WriteLine(a);
        }
    });
}

和 运行 在 linqpad 中多次得到相同的结果

1
2
3
TaskId:15 Result:3
TaskId:14 Result:2
TaskId:13 Result:1

1
2
3
TaskId:18 Result:3
TaskId:17 Result:2
TaskId:16 Result:1

对于那个特定的调用,Task[] 的参数 -- 顺序是 保证的。

事实上,根据 Task.WhenAll(Task[]) 文档,根本没有提及顺序。但是如果你使用 Task.WhenAll(IEnumerable<Task<TResult>>) 重载它读作 follows:

If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state. The Result of the returned task will be set to an array containing all of the results of the supplied tasks in the same order as they were provided (e.g. if the input tasks array contained t1, t2, t3, the output task's Result will return an TResult[] where arr[0] == t1.Result, arr1 == t2.Result, and arr[2] == t3.Result).

当您调用 Task.WhenAll(使用可枚举数组或参数数组)时,结果的顺序与传递给该方法的任务的顺序相匹配。

也就是说,这是真的:

var task1 = PrintNumber(3);
var task2 = PrintNumber(2);
var task3 = PrintNumber(1);
var taskResults = await Task.WhenAll(task1, task2, task3);
// taskResults[0] is the same as task1.Result
// taskResults[1] is the same as task2.Result
// taskResults[2] is the same as task3.Result

然而,ContinueWith 是一个完全不同的故事。 ContinueWith 附加一个延续,这个延续将在任务完成后的某个时间 运行。

在您的特定代码中,您没有将延续附加到传递给 Task.WhenAll 的任务。但如果你是,那么在该任务完成后的任何时候都可以 运行 继续。

旁注,don't use ContinueWith(正如我在我的博客中解释的那样)。只需使用 await 即可;生成的代码更正确、更清晰、更易于维护。