I found out that if construct a new task using the following way:
var task = new Task(async action); task.Start();
,
the any call of any async method (await Task.Delay()
, await new WebClient().DownloadStringAsync()
, etc.) supposingly ignores await
operator and immediately backs to the main thread.
If I run the same action using Task.Run(async action)
way, then the same code works as expected.
Sample code:
class Program
{
static async Task Main()
{
// way1 - it's working
var goodTask = Task.Run(async () => await ProblemMethod("goodTask"));
await goodTask;
Console.WriteLine($"{DateTime.Now:HH:mm:ss} :: {nameof(goodTask)} is finished.");
// way2 - it fails without any exceptions on line with GetRequestStreamAsync
var poorTask = new Task(async () => await ProblemMethod("poorTask"));
poorTask.Start();
await poorTask;
Console.WriteLine($"{DateTime.Now:HH:mm:ss} :: {nameof(poorTask)} is finished.");
Console.ReadLine();
}
static async Task ProblemMethod(string taskName)
{
Console.WriteLine($"{taskName} :: {DateTime.Now:HH:mm:ss} :: It's a first line.");
await Task.Delay(2000);
Console.WriteLine($"{taskName} :: {DateTime.Now:HH:mm:ss} :: It's a last line.");
}
}
Console output:
goodTask :: 18:52:50 :: It's a first line.
goodTask :: 18:52:52 :: It's a last line.
18:52:52 :: goodTask is finished.
poorTask :: 18:52:52 :: It's a first line.
18:52:52 :: poorTask is finished.
poorTask :: 18:52:54 :: It's a last line.
Why so strange behaviour? And, yeah, I know that the preferred and recommended way is to run tasks immediately, via Task.Run or Task.Factory.StartNew, but what should I do if I don't want to run my tasks immediately?
The answer is discussed here. Essentially the Task
construction takes an Action<>
and not a Func<>
and so the async delegate is not really being treated as such.