This question already has an answer here:
When I chain a method using ContinueWith and if that method uses async Action, then why is the chained method not waited for completion when we do Task.WhenAll?
For example following code
var str1 = "str1";
var str2 = "str2";
var task0 = Task.Run( async ()=> {
await Task.Delay(1000);
return "changed";
});
var task1 = task0.ContinueWith(async prevTask => {
await Task.Delay(5000);
str1 = prevTask.Result;
});
var task2 = task0.ContinueWith(prevTask => {
Task.Delay(1000).Wait();
str2 = prevTask.Result;
});
await Task.WhenAll(task0, task1, task2);
Console.WriteLine(str1);
Console.WriteLine(str2);
produces output
str1
changed
But when I try to do same with another task with async action but blocking call to Task.Delay, then that method works fine. For example, adding task 3 as
....
var str3 = "str3";
var task3 = task0.ContinueWith(async prevTask => {
Task.Delay(2500).Wait();
str3 = prevTask.Result;
});
await Task.WhenAll(task0, task1, task2, task3);
Console.WriteLine(str1);
Console.WriteLine(str2);
Console.WriteLine(str3);
produces following output
str1
changed
changed
While debugging, I also saw the state of task1 as 'Ran to completion', which I don't understand why. Seems like await inside ContinueWith is causing the task to assume it has completed, but I don't understand why?
Link to functioning code: http://rextester.com/WFRTKY13796
The type of task1 is Task<Task> so you need to await the tasks to get the resultant set. This is easily done by adding await to the line while the second example uses a blocking call. Here's the modified rexster code:
//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
Test().Wait();
}
public static async Task Test(){
var str1 = "str1_beforeChange";
var str2 = "str2_beforeChange";
var str3 = "str3_beforeChange";
var task0 = Task.Run(async ()=>{
await Task.Delay(2500);
return "afterChange";
});
//await the async continuation
var task1 = await task0.ContinueWith(async prevTask => {
await Task.Delay(5000);
str1 = prevTask.Result;
});
var task2 = task0.ContinueWith(prevTask =>{
Task.Delay(2500).Wait();
str2 = prevTask.Result;
});
var task3 = task0.ContinueWith(prevTask =>{
Task.Delay(1000).Wait();
str3 = prevTask.Result;
});
await Task.WhenAll(task0, task1, task2, task3);
Console.WriteLine(str1);
Console.WriteLine(str2);
Console.WriteLine(str3);
}
}
}
ContinueWithdoes not supportasyncdelegates, thus resulting task represent only first synchronous part of asynchronous delegate. You need to callUnwrap(), if you want get task which represent completion of asynchronous delegate as whole. - PetSerAlContinueWith. You're almost always better off usingawaitto schedule continuations to tasks. UsingContinueWithdirectly is much harder to do correctly. - Servy