Ex, the following code manually instantiates a Task and passes to a Task.WhenAll
in a List<T>
public async Task Do3()
{
var task1 = new Task(async () => { await Task.Delay(2000); Console.WriteLine("########## task1"); });
var taskList = new List<Task>() { task1};
taskList[0].Start();
var taskDone = Task.WhenAll(taskList);
await taskDone;
}
without starting the Task it doesn't work, it hangs forever calling from a console app, but the below works just fine without starting it
public async Task Do3()
{
//var task1 = new Task(async () => { await Task.Delay(2000); Console.WriteLine("########## task1"); });
var taskList = new List<Task>() { SubDo1() };
//taskList[0].Start();
var taskDone = Task.WhenAll(taskList);
await taskDone;
}
public async Task SubDo1()
{
await Task.Delay(2000);
Console.WriteLine("########## task1");
}
CodePudding user response:
Task
is used in two completely different ways here; when you call an async
method: you are starting it yourself; at this point, two things can happen:
- it can run to completion (eventually) without ever reaching a truly asynchronous state, and return a completed (or faulted) task to the caller
- it can reach an incomplete awaitable (in this case
await Task.Delay
), at which point it creates a state machine that represents the current position, schedules a completion operation on that incomplete awaitable (to do whatever comes next), and then returns an incomplete task to the caller
It is not "not started"; to return anything to the caller: we have started it. However, unlike Task.Start()
, we start that work on our current thread - not an external worker thread - with other threads only getting involved based on how that incomplete awaitable schedules the completion callbacks that the compiler gives it.
This is very different to the new Task(...)
scenario, where nothing is initially started. That's why they behave differently. Note also the Remarks section of the Task
constructor here - it is a very niche API, and honestly: not hugely recommended.
Additionally: when you don't immediately await
an async
method, you're essentially going into concurrent territory (assuming the awaitable won't always complete synchronously). In some cases, this matters, and may cause threading problems re race-conditions. It shouldn't matter much in this case, though.