Actualmente estoy leyendo " Concurrencia en C # Cookbook " de Stephen Cleary, y noté la siguiente técnica:
var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
downloadTaskes una llamada a httpclient.GetStringAsyncy se timeoutTaskestá ejecutando Task.Delay.
En el caso de que no se haya agotado el tiempo de espera, entonces downloadTaskya está completado. ¿Por qué es necesario esperar un segundo en lugar de regresar downloadTask.Result, dado que la tarea ya está completada?
c#
asynchronous
async-await
task
julio.g
fuente
fuente

downloadTaskytimeoutTask? ¿Qué hacen?AggregateExceptionconResultvs primera excepción víaExceptionDispatchInfoconawait). Discutido con más detalle en "Task Exception Handling in .NET 4.5" de Stephen Toub: blogs.msdn.com/b/pfxteam/archive/2011/09/28/… )Respuestas:
Ya hay algunas buenas respuestas / comentarios aquí, pero solo para intervenir ...
Hay dos razones por las que prefiero
awaitsobreResult(oWait). La primera es que el manejo de errores es diferente;awaitno envuelve la excepción en unAggregateException. Idealmente, el código asincrónico nunca debería tener que lidiarAggregateExceptionen absoluto, a menos que lo desee específicamente .La segunda razón es un poco más sutil. Como describo en mi blog (y en el libro),
Result/Waitpuede causar interbloqueos y puede causar interbloqueos aún más sutiles cuando se usa en unasyncmétodo . Entonces, cuando estoy leyendo el código y veo unResultoWait, es una señal de advertencia inmediata. LaResult/Waitsolo es correcta si está absolutamente seguro de que la tarea ya se completó. Esto no solo es difícil de ver de un vistazo (en el código del mundo real), sino que también es más frágil para los cambios de código.Eso no quiere decir que
Result/Waitdebe no ser utilizado. Sigo estas pautas en mi propio código:await.Result/Waitsi el código realmente lo requiere. Tal uso probablemente debería tener comentarios.ResultyWait.Tenga en cuenta que (1) es, con mucho, el caso común, de ahí mi tendencia a usar en
awaittodas partes y tratar los otros casos como excepciones a la regla general.fuente
awaitevita laAggregateExceptionenvoltura.AggregateExceptionfue diseñado para programación paralela, no programación asincrónica.Waitera unirse a instancias de Dynamic Task ParallelismTask. Usarlo para esperarTaskinstancias asincrónicas es peligroso. Microsoft consideró introducir un nuevo tipo de "Promesa", pero optó por utilizar el existente en suTasklugar; la compensación de reutilizar elTasktipo existente para tareas asincrónicas es que terminas con varias API que simplemente no deberían usarse en código asincrónico.Esto tiene sentido si
timeoutTaskes un producto deTask.Delaylo que creo que está en el libro.Task.WhenAnydevuelveTask<Task>, donde la tarea interna es una de las que pasó como argumentos. Se podría reescribir así:En cualquier caso, debido a que
downloadTaskya se completó, hay una diferencia mínima entrereturn await downloadTaskyreturn downloadTask.Result. Es en que este último arrojará loAggregateExceptionque envuelve cualquier excepción original, como lo señaló @KirillShlenskiy en los comentarios. El primero simplemente volvería a lanzar la excepción original.En cualquier caso, donde sea que maneje las excepciones, debe verificar
AggregateExceptionsus excepciones internas de todos modos, para llegar a la causa del error.fuente