c# - whenall - Utilice una devolución de llamada asíncrona con Task.ContinueWith
task httpresponsemessage c# (3)
Al encadenar varias tareas con el método ContinueWith
, su tipo de devolución será Task<T>
mientras que T
es el tipo de devolución del delegado / método pasado a ContinueWith
.
Como el tipo de retorno de un delegado asíncrono es una Task
, terminará con una Task<Task>
y terminará esperando que el delegado asíncrono le devuelva la Task
que se realiza después de la primera await
.
Para corregir este comportamiento, debe usar la Task
devuelta, incrustada en su Task<Task>
. Utilice el método de extensión Unwrap
para extraerlo.
Estoy tratando de jugar un poco con C # ''s async / await / continuewith. Mi objetivo es tener que tener 2 tareas que se ejecutan en paralelo, aunque la tarea es ejecutar una secuencia de acciones en orden. Para hacer eso, planeé tener una List<Task>
que representa las 2 (o más) tareas que se ejecutan en paralelo, y usar ContinueWith
con cada una de las Task
Mi problema es que la devolución de llamada en continuar no parece ejecutarse mientras la lista de await taskList
ya ha regresado.
Para resumir, aquí hay una muestra para ilustrar lo que espero que suceda:
class Program
{
static public async Task Test()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static void Main(string[] args)
{
Test().ContinueWith(
async (task) =>
{
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
},
TaskContinuationOptions.AttachedToParent).Wait();
Console.WriteLine("Done with test");
}
}
La salida esperada sería
Enter Test
Leave Test
Enter callback
Leave callback
Done with test
Sin embargo, la salida es
Enter Test
Leave Test
Enter callback
Done with test
¿Hay alguna manera de hacer que la tarea en la que se llama a ContinueWith
se espere a que se complete la función proporcionada antes de que se considere como finalizada? es decir. .Wait esperará a que se completen ambas tareas, la original y la que devuelve ContinueWith
Cuando esté haciendo una programación async
, debe esforzarse por reemplazar ContinueWith
con await
, como tal:
class Program
{
static public async Task Test()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static async Task MainAsync()
{
await Test();
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
}
static void Main(string[] args)
{
MainAsync().Wait();
Console.WriteLine("Done with test");
}
}
El código que utiliza await
es mucho más limpio y fácil de mantener.
Además, no debe usar tareas principales / secundarias con tareas async
(por ejemplo, AttachedToParent
). No fueron diseñados para trabajar juntos.
Me gustaría añadir mi respuesta para complementar la respuesta que ya ha sido aceptada. Dependiendo de lo que intente hacer, a menudo es posible evitar la complejidad adicional de los delegados asíncronos y las tareas envueltas. Por ejemplo, su código podría ser re-factorizado de esta manera:
class Program
{
static async Task Test1()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static async Task Test2()
{
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
}
static async Task Test()
{
await Test1(); // could do .ConfigureAwait(false) if continuation context doesn''t matter
await Test2();
}
static void Main(string[] args)
{
Test().Wait();
Console.WriteLine("Done with test");
}
}