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

时间:2016-02-03 11:41:49

标签: c# asynchronous task-parallel-library

只想知道使用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

2 个答案:

答案 0 :(得分:4)

通过该特定调用,Task[]的参数 - 订单保证。

事实上,根据Task.WhenAll(Task[])文件,没有提到任何顺序。但如果您使用Task.WhenAll(IEnumerable<Task<TResult>>)重载,则会将其读为follows

  

如果没有任何任务出现故障而且没有任何任务被取消,则生成的任务将以RanToCompletion状态结束。返回任务的结果将被设置为一个数组,其中包含所提供任务的所有结果,其顺序与提供的顺序相同(例如,如果输入任务数组包含t1,t2,t3,输出任务的结果将返回一个TResult [],其中arr [0] == t1.Result,arr1 == t2.Result,和arr [2] == t3.Result)。

答案 1 :(得分:2)

当你调用Task.WhenAll(带有enumerable或params数组)时,结果的顺序与传递给该方法的任务的顺序相匹配。

也就是说,这是真的:

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代替;生成的代码更正确,更清晰,更易于维护。