run parallel method library example create await async c# .net lambda async-await task-parallel-library

c# - parallel - Task.Factory.StartNew con async lambda y Task.WaitAll



task parallel library c# (4)

Estoy tratando de usar Task.WaitAll en una lista de tareas. La Tasks.WaitAll es que las tareas son una lambda asíncrona que rompe las Tasks.WaitAll . Espera Tasks.WaitAll ya que nunca espera.

Aquí hay un bloque de código de ejemplo:

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

Esto no espera debido a la lambda asíncrona. Entonces, ¿cómo se supone que debo esperar las operaciones de E / S en mi lambda?


Esto no espera debido a la lambda asíncrona. Entonces, ¿cómo se supone que debo esperar las operaciones de E / S en mi lambda?

La razón por la que Task.WaitAll no espera la finalización del trabajo de E / S presentado por su lambda asíncrona es porque Task.Factory.StartNew realidad devuelve una Task<Task> . Dado que su lista es una List<Task> (y la Task<T> deriva de la Task ), espera en la tarea externa iniciada por StartNew , mientras ignora la interna creada por el lambda asíncrono. Es por eso que dicen Task.Factory.StartNew es peligroso con respecto a async.

¿Cómo puedes arreglar esto? Podría llamar explícitamente a la Task<Task>.Unwrap() para obtener la tarea interna:

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());

O como dijeron otros, podría llamar a Task.Run en Task.Run lugar:

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

Además, dado que desea hacer las cosas bien, querrá usar Task.WhenAll , por qué se puede esperar asincrónicamente, en lugar de Task.WaitAll que bloquea sincrónicamente:

await Task.WhenAll(tasks);


Puedes hacer así.

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... } }


tienes que usar el método Task.ContinueWith . Me gusta esto

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


Task.Factory.StartNew no reconoce a los delegados async ya que no hay sobrecarga que acepte una función que devuelve una Task .

Esta más otras razones (ver StartNew es peligroso ) es la razón por la que deberías usar Task.Run aquí:

tasks.Add(Task.Run(async () => ...