La mia libreria di attività asincrone dovrebbe ingoiare tranquillamente le eccezioni?

10

Ho appena appreso che .NET 4.5 ha introdotto una modifica al modo in cui vengono gestite le eccezioni all'interno di Task . Cioè, sono silenziosamente soppressi.

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

In .NET 4.5, Tasks have significantly more prominence than they did in .NET 4, as they’re baked in to the C# and Visual Basic languages as part of the new async features supported by the languages. This in effect moves Tasks out of the domain of experienced developers into the realm of everyone. As a result, it also leads to a new set of tradeoffs about how strict to be around exception handling.

( fonte )

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

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

    
posta Roman Starkov 25.04.2013 - 12:41
fonte

2 risposte

2

Per quello che vale, il documento che hai collegato a ti dà un caso esemplificativo come giustificazione:

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

In this code, the developer is launching two asynchronous operations to run in parallel, and is then asynchronously waiting for each using the new await language feature...[C]onsider what will happen if both op1 and op2 fault. Awaiting op1 will propagate op1’s exception, and therefore op2 will never be awaited. As a result, op2’s exception will not be observed, and the process would eventually crash.

To make it easier for developers to write asynchronous code based on Tasks, .NET 4.5 changes the default exception behavior for unobserved exceptions. While unobserved exceptions will still cause the UnobservedTaskException event to be raised (not doing so would be a breaking change), the process will not crash by default. Rather, the exception will end up getting eaten after the event is raised, regardless of whether an event handler observes the exception.

Non ne sono convinto. Rimuove la possibilità di un errore non ambiguo, ma difficile da tracciare (arresto anomalo del programma che potrebbe verificarsi a lungo dopo l'errore effettivo), 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, naturalmente, il 99% degli sviluppatori utilizzerà solo il comportamento predefinito, senza mai pensare a questo problema. Quindi quello che hanno selezionato come predefinito è un grosso problema.

    
risposta data 25.04.2013 - 14:01
fonte
2

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

Diamo un'occhiata alle ipotesi.

  • La tua fede cieca

I've learned to trust that many of the decisions in .NET were made by people who really know what they're doing, and there is usually a very good reason behind things they decide. But this one escapes me.

MS ha delle persone davvero brillanti nel personale, senza dubbio. Hanno anche un certo numero di manager e dirigenti che sono ... incapaci 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ù triste.

Il mio punto è che, se il tuo istinto ti dice che qualcosa potrebbe essere sbagliato, allora c'è una buona 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. In modo approssimativo, un'eccezione è un errore. La presentazione dell'errore, anche se mal formattata, fornisce informazioni critiche all'utente finale. Vale a dire, qualcosa è andato storto.

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

User: The app is broken.
Dev: What's broken?
User: I dunno, I click on the button and nothing happens.
Dev: What do you mean by nothing happens?
User: Look, I click, I wait, and I wait, and I wait, and nothing... it's obviously broken.

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 di networking OSI - > trasmissione fisica - > eseguire il backup dei 7 livelli di networking OSI - > servizio di ricezione - > metodo chiamato dal servizio - > ... - > risposta di risposta inviata dal servizio - > .... - > ricevuta asynch - > elaborazione di una risposta asynch - > ...

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

Dopo aver affrontato alcune delle ipotesi sottostanti, penso che diventi più chiaro il motivo per cui sopprimere silenziosamente le eccezioni è una cattiva idea. Un'eccezione e un messaggio di errore associato indicano agli 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 capire 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 farà crashare la tua applicazione. Sopprimendo le eccezioni, l'applicazione non si arresta in modo anomalo. C'è una certa validità in questo però poiché il punto di async è quello di consentire all'applicazione di continuare a lavorare mentre i dati vengono recuperati. Non è tanto un'estensione logica a dire che se si potesse continuare a operare mentre si aspettano i risultati, allora un errore nel recupero non dovrebbe mandare in crash l'applicazione - la chiamata asincrona viene implicitamente dichiarata come non abbastanza importante per terminare l'applicazione. / p>

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

Quindi la mia valutazione finale è che questo è un mezzo tentativo di risolvere un problema creato spingendo le persone in un modello asincrono quando non erano pronte a spostare il loro pensiero su quell'approccio.

    
risposta data 25.04.2013 - 15:57
fonte

Leggi altre domande sui tag