Task.Factory.StartNew with asynchronous lambda and Task.WaitAll

I am trying to use Task.WaitAll in a task list. The fact of the matter is that the task is an asynchronous lambda that breaks Tasks.WaitAll since it never waits.

Here is a sample code:

 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 does not wait due to asynchronous lambda. So, how should I wait for I / O operations in my lambda?

+7
c # task-parallel-library async-await
source share
4 answers

Task.Factory.StartNew does not recognize async delegates, because there is no overload that accepts a function that returns Task .

This is plus other reasons (see StartNew is dangerous ), so you should use Task.Run here:

 tasks.Add(Task.Run(async () => ... 
+10
source share

This does not wait due to asynchronous lambda. So, how should I wait for I / O operations in my lambda?

The reason Task.WaitAll does not wait for the IO represented by your asynchronous lambda to complete, because Task.Factory.StartNew actually returns a Task<Task> . Since your list is a List<Task> (and Task<T> comes from Task ), you expect from an external task starting with StartNew , and ignoring the internal one created by the asynchronous lambda. That's why they say that Task.Factory.StartNew is dangerous in relation to async.

How could you fix this? You can explicitly call Task<Task>.Unwrap() to get the internal task:

 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... } }).Unwrap()); 

Or, as others have said, you can call Task.Run instead:

 tasks.Add(Task.Run(async () => /* lambda */); 

Also, since you want to do everything right, you need to use Task.WhenAll , which is why it is required asynchronously, instead of Task.WaitAll , which synchronously blocks:

 await Task.WhenAll(tasks); 
+9
source share

You can do it.

  void Something() { List<Task> tasks = new List<Task>(); tasks.Add(ReadAsync()); Task.WaitAll(tasks.ToArray()); } async Task ReadAsync() { using (dbContext = new DatabaseContext()) { var records = await dbContext.Where(r => r.Id = 100).ToListAsync(); //do long cpu process here... } } 
0
source share

you need to use the Task.ContinueWith method. Like this

 List<Task> tasks = new List<Task>(); tasks.Add(Task.Factory.StartNew(() => { using (dbContext = new DatabaseContext()) { return dbContext.Where(r => r.Id = 100).ToListAsync().ContinueWith(t => { var records = t.Result; // do long cpu process here... }); } } } 
-one
source share

All Articles