Task.WhenAny y excepciones no observadas
-
12-12-2019 - |
Pregunta
Digamos que tengo tres tareas, a
, b
, y c
.Se garantiza que los tres generarán una excepción en un tiempo aleatorio entre 1 y 5 segundos.Luego escribo el siguiente código:
await Task.WhenAny(a, b, c);
En última instancia, esto generará una excepción de cualquier tarea que falle primero.ya que no hay try...catch
aquí, esta excepción aparecerá en algún otro lugar de mi código.
¿Qué sucede cuando las dos tareas restantes generan una excepción?¿No son estas excepciones no observadas las que provocarán la finalización de todo el proceso?¿Eso significa que la única forma de utilizar WhenAny
está dentro de un try...catch
bloquear y luego observar de alguna manera las dos tareas restantes antes de continuar?
Hacer un seguimiento: Me gustaría que la respuesta se aplique tanto a .NET 4.5 y .NET 4.0 con Async Targeting Pack (aunque claramente usando TaskEx.WhenAny
en ese caso).
Solución
¿Qué sucede cuando las dos tareas restantes generan una excepción?
Aquellos Task
s se completará en un estado defectuoso.
¿No son estas excepciones no observadas las que provocarán la finalización de todo el proceso?
Ya no.
En .NET 4.0, el Task
el destructor pasaría su excepción no observada a TaskScheduler.UnobservedTaskException
, lo que finalizaría el proceso si no se controla.
En .NET 4.5, esto el comportamiento fue cambiado.Ahora, las excepciones no observadas se pasan a TaskScheduler.UnobservedTaskException
, pero luego se ignoran si no se controlan.
Otros consejos
Sí, las excepciones de tareas restantes no se observan.Antes de .NET 4.5, está obligado a observarlos (no estoy seguro de cómo es la situación en .NET 4.5, pero cambió).
Normalmente escribo un método auxiliar para tareas de disparar y olvidar como estas:
public static void IgnoreUnobservedExceptions(this Task task)
{
if (task.IsCompleted)
{
if (task.IsFaulted)
{
var dummy = task.Exception;
}
return;
}
task.ContinueWith(t =>
{
var dummy = t.Exception;
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
}
Es posible que desee incluir el inicio de sesión en aplicaciones de producción.