I'm trying to use Task.WaitAll
on a list of tasks. The thing is the tasks are an async lambda which breaks Tasks.WaitAll
as it never waits.
Here is an example code block:
List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(async () =>
{
using (dbContext = new DatabaseContext())
{
var records = await dbContext.Where(r => r.Id = 100).ToListAsync();
//do long cpu process here...
}
}
Task.WaitAll(tasks);
//do more stuff here
This doesn't wait because of the async lambda. So how am I supposed to await I/O operations in my lambda?
you have to use the
Task.ContinueWith
method. Like thisYou can do like this.
The reason
Task.WaitAll
doesn't wait for the completion of the IO work presented by your async lambda is becauseTask.Factory.StartNew
actually returns aTask<Task>
. Since your list is aList<Task>
(andTask<T>
derives fromTask
), you wait on the outer task started byStartNew
, while ignoring the inner one created by the async lambda. This is why they sayTask.Factory.StartNew
is dangerous with respect to async.How could you fix this? You could explicitly call
Task<Task>.Unwrap()
in order to get the inner task:Or like others said, you could call
Task.Run
instead:Also, since you want to be doing things right, you'll want to use
Task.WhenAll
, why is asynchronously waitable, instead ofTask.WaitAll
which synchronously blocks:Task.Factory.StartNew
doesn't recogniseasync
delegates as there is no overload that accepts a function returning aTask
.This plus other reasons (see StartNew is dangerous) is why you should be using
Task.Run
here: