Reputation: 2837
Just want to know what is the order of the task result when using WhenAll and ContinueWith. Are these results gurenteed to be in the same order with task Id?
I wrote below code
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);
}
});
}
and run that several times in linqpad getting the same result
1
2
3
TaskId:15 Result:3
TaskId:14 Result:2
TaskId:13 Result:1
or
1
2
3
TaskId:18 Result:3
TaskId:17 Result:2
TaskId:16 Result:1
Upvotes: 4
Views: 2455
Reputation: 456537
When you call Task.WhenAll
(with either an enumerable or a params array), the order of the results match the order of the tasks passed to that method.
That is to say, this is true:
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
However, ContinueWith
is an entirely different story. ContinueWith
attaches a continuation, and this continuation will run sometime after the task completes.
In your particular code, you're not attaching a continuation to the task passed to Task.WhenAll
. But if you were, then that continuation could run anytime after that task completed.
On a side note, don't use ContinueWith
(as I explain on my blog). Just use await
instead; the resulting code is more correct, cleaner, and easier to maintain.
Upvotes: 4
Reputation: 24525
With that specific invocation, the argument of a Task[]
-- the order is not guaranteed.
In fact, according to the Task.WhenAll(Task[])
documentation there is no mention of order whatsoever. But if you use the Task.WhenAll(IEnumerable<Task<TResult>>)
overload it reads as 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).
Upvotes: 6