¿Debería mi biblioteca de tareas asincrónicas tragar excepciones silenciosamente?

10

Acabo de enterarme de que .NET 4.5 introdujo un cambio en cómo Taskse manejan las excepciones dentro de a . A saber, son silenciosamente reprimidos.

El razonamiento oficial de por qué esto se hizo parece ser "queríamos ser más amigables con los desarrolladores sin experiencia":

En .NET 4.5, las tareas tienen mucha más importancia que en .NET 4, ya que están integradas en los lenguajes C # y Visual Basic como parte de las nuevas funciones asíncronas compatibles con los lenguajes. Esto, en efecto, mueve las tareas fuera del dominio de desarrolladores experimentados al dominio de todos. Como resultado, también conduce a un nuevo conjunto de compensaciones sobre cuán estricto debe ser el manejo de excepciones.

( fuente )

He aprendido a confiar en que muchas de las decisiones en .NET fueron tomadas por personas que realmente saben lo que están haciendo, y generalmente hay una muy buena razón detrás de las cosas que deciden. Pero este se me escapa.

Si estuviera diseñando mi propia biblioteca de tareas asíncrona, ¿cuál es la ventaja de tragar excepciones que los desarrolladores de Framework vieron que no estoy viendo?

Roman Starkov
fuente
44
+1. Buena pregunta, dado el hecho de que no propagar excepciones que no puede manejar es una mala práctica, incluso al margen del contexto asincrónico. Además, el argumento sobre los desarrolladores inexpertos es bastante flojo, en mi humilde opinión. ¿Qué sería más incómodo para los principiantes que un código que no solo no funciona, sino que tampoco arroja ninguna excepción?
Arseni Mourzenko
@MainMa Exactamente mis pensamientos, pero me he equivocado antes (cuando resultó que, de hecho, tenían una razón muy buena pero poco obvia), así que pensé en preguntar.
Roman Starkov
2
Wow, me alegro de que hayas publicado esto solo porque es lo primero que he oído de él; y definitivamente viola POLA . Tienes razón en que esos tipos realmente saben lo que están haciendo, así que tengo curiosidad por saber qué razonamiento podría estar detrás de esto ... Me pregunto si tiene una razón más técnica basada en la implementación de Async y cómo se propagarían las excepciones. como fondo pasando a una corutina ..
Jimmy Hoffa

Respuestas:

2

Por lo que vale, el documento al que se vinculó ofrece un caso de ejemplo como justificación:

Task op1 = FooAsync(); 
Task op2 = BarAsync(); 
await op1; 
await op2;

En este código, el desarrollador está lanzando dos operaciones asincrónicas para que se ejecuten en paralelo, y luego está asincrónicamente esperando que cada una use la nueva función de idioma de espera ... [C] considerando qué sucederá si fallan tanto op1 como op2. La espera de op1 propagará la excepción de op1 y, por lo tanto, nunca se esperará op2. Como resultado, no se observará la excepción de op2 y el proceso finalmente se bloqueará.

Para facilitar a los desarrolladores escribir código asincrónico basado en tareas, .NET 4.5 cambia el comportamiento de excepción predeterminado para excepciones no observadas. Si bien las excepciones no observadas seguirán provocando el evento UnobservedTaskException (no hacerlo sería un cambio rotundo), el proceso no se bloqueará de manera predeterminada. Por el contrario, la excepción terminará siendo comida después de que se produzca el evento, independientemente de si un controlador de eventos observa la excepción.

No estoy convencido por esto. Elimina la posibilidad de un error inequívoco, pero difícil de rastrear (misterioso bloqueo del programa que puede ocurrir mucho después del error real), pero lo reemplaza con la posibilidad de un error completamente silencioso, que podría convertirse en un problema igualmente difícil de rastrear más adelante en tu programa. Eso me parece una elección dudosa.

El comportamiento es configurable, pero, por supuesto, el 99% de los desarrolladores solo usarán el comportamiento predeterminado, sin pensar en este problema. Entonces, lo que seleccionaron como predeterminado es un gran problema.


fuente
Pero que hace que obtenga una excepción normal op1, ¿verdad? Si ese no se maneja, hará caer el proceso, ¿verdad?
Timwi
1
@Timwi, según tengo entendido, ni op1la excepción ni op2la excepción derribarían el programa. La ventaja es que tienes la oportunidad de observar ambos. Pero si no lo haces, ambos serán tragados. Sin embargo, podría estar equivocado.
Estoy realmente sorprendido de que les parezca tan importante permitirte "observar" ambos. ¡Si quiere "observarlos", los atrapa e informa su ocurrencia a través del resultado de la tarea! ... De acuerdo con su razonamiento, +1
Roman Starkov
2

TL; DR - No , no debes ignorar las excepciones en silencio.


Veamos los supuestos.

  • Tu fe ciega

He aprendido a confiar en que muchas de las decisiones en .NET fueron tomadas por personas que realmente saben lo que están haciendo, y generalmente hay una muy buena razón detrás de las cosas que deciden. Pero este se me escapa.

MS tiene algunas personas realmente brillantes en el personal, sin duda. También tienen una serie de gerentes y ejecutivos que no tienen ni idea, y que constantemente toman malas decisiones. Por mucho que nos gustaría creer el cuento de hadas del científico técnicamente experto que dirige el desarrollo del producto, la realidad es mucho más sombría.

Mi punto es que, si tu instinto te dice que algo puede estar mal, entonces hay una buena posibilidad (y un precedente anterior) de que esté mal.

  • Que este es un problema técnico

Cómo manejar las excepciones en este caso es una decisión de factores humanos, no una decisión técnica. En términos generales, una excepción es un error. La presentación del error, incluso si está mal formateada, proporciona información crítica al usuario final. A saber, algo salió mal.

Considere esta conversación hipotética entre un usuario final y un desarrollador.

Usuario: la aplicación está rota.
Dev: ¿Qué está roto?
Usuario: No sé, hago clic en el botón y no pasa nada.
Dev: ¿Qué quieres decir con que no pasa nada ?
Usuario: Mira, hago clic, espero, y espero, y espero, y nada ... obviamente está roto.

Nuestro pobre desarrollador, afortunadamente hipotético, ahora tiene que descubrir qué salió mal en la cadena de eventos. ¿Donde estaba?
Notificación del controlador de eventos -> Rutina para manejar el evento -> Método activado por el controlador -> inicio de llamada asincrónica -> las 7 capas de redes OSI -> transmisión física -> copia de seguridad de las 7 capas de redes OSI -> servicio de recepción -> método llamado por servicio -> ... -> respuesta devuelta enviada por servicio -> .... -> recibo asíncrono -> procesamiento de respuesta asíncrona -> ...

Y tenga en cuenta que he pasado por alto varias rutas de error potenciales allí.


Después de abordar algunos de los supuestos subyacentes, creo que queda más claro por qué suprimir silenciosamente las excepciones es una mala idea. Una excepción y un mensaje de error asociado es un indicador clave para los usuarios de que algo salió mal. Incluso si el mensaje no tiene sentido para el usuario final, la información incrustada puede ser útil para el Desarrollador para comprender qué salió mal. Si tienen suerte, el mensaje incluso conducirá a la solución.

Creo que parte del problema aquí es que una excepción manejada incorrectamente bloqueará su aplicación. Al suprimir las excepciones, la aplicación no se bloqueará. Sin embargo, esto tiene cierta validez, ya que el objetivo de la sincronización es permitir que la aplicación siga funcionando mientras se recuperan los datos. No es una gran extensión lógica decir que si pudiera seguir operando mientras espera los resultados, una falla en la recuperación tampoco debería bloquear la aplicación: la llamada asíncrona se declara implícitamente como no lo suficientemente importante como para finalizar la aplicación.

Entonces es una solución, pero está resolviendo el problema incorrecto. No hace falta mucho esfuerzo para proporcionar un contenedor para el manejo de excepciones para que la aplicación pueda seguir ejecutándose. Se detecta la excepción, se arroja un mensaje de error a la pantalla o se registra, y la aplicación puede seguir ejecutándose. Suprimir la excepción implica que ignorar los errores será A-OK y que su prueba garantizará que las excepciones nunca escapen al campo de todos modos.

Entonces, mi evaluación final es que este es un intento a medias para resolver un problema creado al empujar a las personas a un modelo asincrónico cuando no estaban listas para cambiar su pensamiento hacia ese enfoque.


fuente