c# - remarks - Por qué la Tarea termina incluso en espera
remarks c# (3)
Hay excelentes respuestas aquí, pero me gustaría señalar lo obvio: Task.Factory.StartNew
es completamente redundante, innecesario y se usa incorrectamente.
Si reemplazas
Task newTask = Task.Factory.StartNew(MainTask);
con
Task newTask = MainTask();
Obtendrás exactamente el comportamiento que esperas, sin perder otro hilo de subprocesos solo para iniciar otro subproceso de subprocesos. De hecho, si quisiera reescribir su ejemplo para ser más idiomático, usaría algo como esto:
static void Main (string[] args)
{
var task =
MainTask()
.ContinueWith(t => Console.WriteLine("Main State={0}", t.Status));
task.Wait();
}
static async Task MainTask()
{
Console.WriteLine ("MainStarted!");
await Task.Delay(1000);
Console.WriteLine ("Waiting Ended!!");
throw new Exception ("CustomException!");
Console.WriteLine ("NeverReaches here!!");
}
Este código solo usa una secuencia de grupo de subprocesos para el código después de la demora y vuelve a lanzar la excepción en la llamada task.Wait()
; es posible que desee hacer otra cosa, por supuesto.
Como nota al margen, incluso si no desea esperar explícitamente a que la tarea finalice, no debe usar while (true) {}
para evitar que la aplicación finalice; una simple Console.ReadLine()
funcionará solo también, y no va a impulsar uno de sus núcleos de CPU al 100% de utilización :)
Tengo un problema en el siguiente código:
static void Main (string[] args)
{
Task newTask = Task.Factory.StartNew(MainTask);
newTask.ContinueWith ((Task someTask) =>
{
Console.WriteLine ("Main State=" + someTask.Status.ToString () + " IsFaulted=" + someTask.IsFaulted+" isComplete="+someTask.IsCompleted);
});
while (true)
{
}
}
static async Task MainTask()
{
Console.WriteLine ("MainStarted!");
Task someTask = Task.Factory.StartNew (() =>
{
Console.WriteLine ("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine ("SleepEnded!");
});
await someTask;
Console.WriteLine ("Waiting Ended!!");
throw new Exception ("CustomException!");
Console.WriteLine ("NeverReaches here!!");
}
Solo quiero obtener Exception de la nueva tarea iniciada MainTask
. Pero el resultado no fue el esperado.
MainStarted!
Main State = RanToCompletion IsFaulted = False isComplete = True
SleepStarted!
SleepEnded!
Waiting Ended!!
Como puede ver el resultado, la tarea finaliza antes de "¡La espera ha terminado!" registro de consola No tengo ni idea de por qué MainTask
terminó incluso si MainTask
await
comando adentro. ¿Me perdí algo?
Modifiqué tu problema aquí para captar las excepciones.
static void Main(string[] args)
{
DoFoo();
Console.ReadKey();
}
static async void DoFoo()
{
try
{
await Foo();
}
catch (Exception ex)
{
//This is where you can catch your exception
}
}
static async Task Foo()
{
await MainTask().ContinueWith((Task someTask) =>
{
Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted);
}, TaskContinuationOptions.NotOnFaulted);
}
static async Task MainTask()
{
Console.WriteLine("MainStarted!");
Task someTask = Task.Run(() =>
{
Console.WriteLine("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine("SleepEnded!");
});
await someTask;
throw new Exception("CustomException!");
Console.WriteLine("Waiting Ended!!");
}
debe usar TaskContinuationOptions.NotOnFaulted
que significa que la tarea continuar con solo se ejecutará si la tarea primaria no tuvo excepciones.
Task.Factory.StartNew
no entiende los delegados asíncronos, por lo que debe usar Task.Run
en este caso y la excepción debería fluir.
Task.Factory.StartNew(MainTask);
es esencialmente equivalente a
Task.Factory.StartNew(() => MainTask);
que ignora la tarea devuelta desde MainTask
y la excepción simplemente se traga.
Vea esta publicación en el blog para más detalles.
Intenta usar Task.Run
en Task.Run
lugar y obtendrás tu excepción:
void Main(string[] args)
{
Task newTask = Task.Run(MainTask);
newTask.ContinueWith((Task someTask) =>
{
Console.WriteLine("Main State=" + someTask.Status.ToString() + " IsFaulted=" + someTask.IsFaulted + " isComplete=" + someTask.IsCompleted);
});
while (true)
{
}
}
static async Task MainTask()
{
Console.WriteLine("MainStarted!");
Task someTask = Task.Run(() =>
{
Console.WriteLine("SleepStarted!");
Thread.Sleep(1000);
Console.WriteLine("SleepEnded!");
});
await someTask;
Console.WriteLine("Waiting Ended!!");
throw new Exception("CustomException!");
Console.WriteLine("NeverReaches here!!");
}