La mia libreria di attività asincrone dovrebbe inghiottire le eccezioni in silenzio?


10

Ho appena appreso che .NET 4.5 ha introdotto una modifica al modo in cui Taskvengono gestite le eccezioni all'interno di a . Vale a dire, vengono soppressi in silenzio.

Il ragionamento ufficiale del perché ciò è stato fatto sembra essere "volevamo essere più amichevoli con gli sviluppatori inesperti":

In .NET 4.5, le attività hanno un'importanza notevolmente maggiore rispetto a .NET 4, poiché vengono inserite nei linguaggi C # e Visual Basic come parte delle nuove funzionalità asincrone supportate dalle lingue. Questo in effetti sposta le attività fuori dal dominio degli sviluppatori esperti nel regno di tutti. Di conseguenza, porta anche a una nuova serie di compromessi sulla rigidità della gestione delle eccezioni.

( fonte )

Ho imparato a fidarmi che molte delle decisioni in .NET sono state prese da persone che sanno davvero cosa stanno facendo, e di solito c'è una ragione molto buona dietro le cose che decidono. Ma questo mi sfugge.

Se stavo progettando la mia libreria di attività asincrone, qual è il vantaggio di ingoiare eccezioni che gli sviluppatori del Framework hanno visto che non vedo?


4
+1. Buona domanda, dato che non propagare le eccezioni che non si possono gestire è una cattiva pratica anche a parte il contesto asincrono. Inoltre, l'argomento sugli sviluppatori inesperti è piuttosto scadente, IMHO. Cosa sarebbe più imbarazzante per i principianti di un pezzo di codice che non solo non funziona, ma non genera eccezioni?
Arseni Mourzenko,

@MainMa Esattamente i miei pensieri, ma in precedenza ho sbagliato (quando si è scoperto che avevano, in effetti, una ragione molto buona ma non ovvia), quindi ho pensato di chiedere.
Roman Starkov,

2
Wow, sono contento che tu l'abbia pubblicato solo perché è il primo che ne ho sentito parlare; e viola definitivamente POLA . Hai ragione sul fatto che quei ragazzi sanno davvero cosa stanno facendo, quindi sono sinceramente curioso di sapere quale potrebbe essere il ragionamento dietro questo ... Mi chiedo se ha un motivo più tecnico basato sull'implementazione di Async e su come si propagheranno le eccezioni come fondo viene passato a un coroutine ..
Jimmy Hoffa

Risposte:


2

Per quello che vale, il documento a cui hai collegato fornisce un caso esemplificativo come giustificazione:

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

In questo codice, lo sviluppatore sta avviando due operazioni asincrone da eseguire in parallelo, quindi sta aspettando in modo asincrono ognuna usando la nuova funzione del linguaggio di attesa ... [C] considera cosa accadrà se si verifica un errore sia op1 che op2. In attesa di op1 si propagherà l'eccezione di op1, e quindi op2 non sarà mai atteso. Di conseguenza, l'eccezione di op2 non verrà osservata e il processo potrebbe arrestarsi in modo anomalo.

Per facilitare agli sviluppatori la scrittura di codice asincrono in base alle attività, .NET 4.5 modifica il comportamento delle eccezioni predefinito per le eccezioni non osservate. Mentre le eccezioni non osservate causeranno comunque la generazione dell'evento UnobservedTaskException (in caso contrario si tratterebbe di una modifica non definitiva), il processo non si arresterà in modo anomalo per impostazione predefinita. Piuttosto, l'eccezione finirà per essere divorata dopo che l'evento è stato generato, indipendentemente dal fatto che un gestore di eventi osservi l'eccezione.

Non ne sono convinto. Rimuove la possibilità di un errore non ambiguo, ma difficile da rintracciare (arresto anomalo del programma che potrebbe verificarsi molto tempo dopo l'errore reale), ma lo sostituisce con la possibilità di un errore completamente silenzioso, che potrebbe diventare un problema altrettanto difficile da rintracciare in seguito nel tuo programma. Mi sembra una scelta dubbia.

Il comportamento è configurabile, ma ovviamente il 99% degli sviluppatori utilizzerà il comportamento predefinito, senza mai pensare a questo problema. Quindi quello che hanno selezionato come predefinito è un grosso problema.


Ma si fa ottenere un'eccezione normale per op1, giusto? Se che uno resti non gestita, che sarà abbattere il processo, giusto?
Timwi,

1
@Timwi, a quanto ho capito, né op1l'eccezione né op2l'eccezione farebbero cadere il programma. Il vantaggio è che hai l'opportunità di osservare entrambi. Ma se non lo fai, saranno entrambi ingoiati. Potrei sbagliarmi però.

Sono davvero sorpreso che trovino così importante lasciarti "osservare" entrambi. Se vuoi "osservarli", li catturi e li riferisci sulla loro occorrenza tramite il risultato del compito! ... Concorda con il tuo ragionamento, +1
Roman Starkov

2

TL; DR - No , non dovresti semplicemente ignorare le eccezioni in silenzio.


Diamo un'occhiata alle ipotesi.

  • La tua cieca fede

Ho imparato a fidarmi che molte delle decisioni in .NET sono state prese da persone che sanno davvero cosa stanno facendo, e di solito c'è una ragione molto buona dietro le cose che decidono. Ma questo mi sfugge.

La SM ha alcune persone davvero brillanti nello staff, senza dubbio. Hanno anche un numero di manager e dirigenti che sono ... all'oscuro e che prendono costantemente decisioni sbagliate. Per quanto vorremmo credere alla fiaba dello scienziato tecnicamente esperto che guida lo sviluppo del prodotto, la realtà è molto più cupa.

Il punto è che, se il tuo istinto ti dice che qualcosa potrebbe essere sbagliato, allora ci sono buone possibilità (e precedenti precedenti) che sia sbagliato.

  • Che questo è un problema tecnico

Come gestire le eccezioni in questo caso è una decisione sui fattori umani, non una decisione tecnica. Liberamente, un'eccezione è un errore. La presentazione dell'errore, anche se scarsamente formattata, fornisce informazioni critiche all'utente finale. Vale a dire, qualcosa è andato storto.

Considera questa ipotetica conversazione tra l'utente finale e uno sviluppatore.

Utente: l'app non funziona.
Dev: Che cosa è rotto?
Utente: Non lo so, faccio clic sul pulsante e non succede nulla.
Dev: Cosa intendi con niente accade?
Utente: Senti, clicco, aspetto e aspetto e aspetto, e nulla ... ovviamente è rotto.

Il nostro povero, fortunatamente ipotetico Sviluppatore, ora deve capire cosa è andato storto nella catena di eventi. Dov'era?
Notifica del gestore eventi -> Routine per gestire l'evento -> Metodo attivato dal gestore -> inizio della chiamata asincrona -> i 7 livelli della rete OSI -> trasmissione fisica -> backup dei 7 livelli della rete OSI -> servizio di ricezione -> metodo chiamato dal servizio -> ... -> restituisci risposta inviata dal servizio -> .... -> ricevuta asincrona -> elaborazione della risposta asincrona -> ...

E tieni presente che ho esaminato diversi potenziali percorsi di errore lì.


Dopo aver affrontato alcune delle ipotesi sottostanti, penso che divenga più chiaro il motivo per cui sopprimere silenziosamente le eccezioni sia una cattiva idea. Un'eccezione e un messaggio di errore associato sono un indicatore chiave per gli utenti che qualcosa è andato storto. Anche se il messaggio non ha senso per l'utente finale, le informazioni incorporate possono essere utili allo sviluppatore per comprendere cosa è andato storto. Se sono fortunati, il messaggio porterà persino alla soluzione.

Penso che parte del problema qui sia che un'eccezione gestita in modo errato causerà l'arresto anomalo dell'applicazione. Sopprimendo le eccezioni, l'applicazione non si arresta in modo anomalo. Vi è una certa validità in questo, tuttavia, poiché il punto di asincrono è consentire all'applicazione di continuare a funzionare durante il recupero dei dati. Non è un'estensione logica dire che se si potesse continuare a operare in attesa dei risultati, neanche un errore nel recupero non dovrebbe arrestare in modo anomalo l'applicazione - la chiamata asincrona viene implicitamente dichiarata come non abbastanza importante per terminare l'applicazione.

Quindi è una soluzione, ma sta risolvendo il problema sbagliato. Non ci vuole molto sforzo per fornire un wrapper alla gestione delle eccezioni in modo che l'applicazione possa rimanere in esecuzione. L'eccezione viene rilevata, il messaggio di errore viene gettato sullo schermo o registrato e l'applicazione può continuare a funzionare. Sopprimere l'eccezione implica che ignorare gli errori sarà A-OK e che il test farà in modo che le eccezioni non sfuggano comunque al campo.

Quindi la mia valutazione finale è che si tratta di un tentativo semi-risoluto di risolvere un problema creato spingendo le persone in un modello asincrono quando non erano pronti a spostare il loro pensiero su quell'approccio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.