Tengo un async
método que no devuelve datos:
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
Llamo a esto desde otro método que devuelve algunos datos:
public string GetStringData()
{
MyAsyncMethod(); // this generates a warning and swallows exceptions
return "hello world";
}
Llamar MyAsyncMethod()
sin esperar provoca una advertencia " Debido a que esta llamada no se espera, el método actual continúa ejecutándose antes de que se complete la llamada " en Visual Studio. En la página de esa advertencia dice:
Debería considerar suprimir la advertencia solo si está seguro de que no desea esperar a que se complete la llamada asincrónica y que el método llamado no generará ninguna excepción .
Estoy seguro de que no quiero esperar a que se complete la llamada; No necesito ni tengo tiempo para hacerlo. Pero la llamada podría generar excepciones.
Me he topado con este problema varias veces y estoy seguro de que es un problema común que debe tener una solución común.
¿Cómo llamo con seguridad a un método asíncrono sin esperar el resultado?
Actualizar:
Para las personas que sugieren que solo espero el resultado, este es un código que responde a una solicitud web de nuestro servicio web (API web ASP.NET). La espera en un contexto de IU mantiene el subproceso de IU libre, pero en una llamada de solicitud web esperará a que finalice la tarea antes de responder a la solicitud, aumentando así los tiempos de respuesta sin motivo.
fuente
MyAsyncMethod().Wait()
Respuestas:
Si desea obtener la excepción "asincrónicamente", puede hacer lo siguiente:
Esto le permitirá lidiar con una excepción en un hilo que no sea el hilo "principal". Esto significa que no tiene que "esperar" la llamada
MyAsyncMethod()
desde el hilo que llamaMyAsyncMethod
; pero aún le permite hacer algo con una excepción, pero solo si ocurre una excepción.Actualizar:
técnicamente, podrías hacer algo similar con
await
:... que sería útil si necesita utilizar específicamente
try
/catch
(ousing
), pero creo que elContinueWith
ser un poco más explícito porque hay que saber quéConfigureAwait(false)
medios.fuente
Task
Convertí esto en un método de extensión en : public static class AsyncUtility {public static void PerformAsyncTaskWithoutAwait (this Task task, Action <Task> exceptionHandler) {var dummy = task.ContinueWith (t => exceptionHandler (t), TaskContinuationOptions.OnlyOnFaulted); }} Uso: MyAsyncMethod (). PerformAsyncTaskWithoutAwait (t => log.ErrorFormat ("Se produjo un error al llamar a MyAsyncMethod: \ n {0}", t.Exception));ConfiguratAwait(false)
no se ejecuta hasta que se completa la tarea, pero el hilo actual no "espera" (es decir, bloquea) para eso, la siguiente línea se llama de forma asíncrona a la invocación de espera. SinConfigureAwait(false)
eso, la siguiente línea se ejecutaría en el contexto de solicitud web original. Con elConfigurateAwait(false)
se ejecuta en el mismo contexto que el método asincrónico (tarea), liberando el contexto / hilo original para continuar ...Primero debe considerar hacer
GetStringData
unasync
método y hacer que leawait
devuelva la tareaMyAsyncMethod
.Si está absolutamente seguro de que no necesita manejar excepciones
MyAsyncMethod
o saber cuándo se completa, puede hacer esto:Por cierto, este no es un "problema común". Es muy raro querer ejecutar algún código y no importa si se completa y no importa si se completa con éxito.
Actualizar:
Dado que está en ASP.NET y desea regresar temprano, puede encontrar útil mi publicación de blog sobre el tema . Sin embargo, ASP.NET no fue diseñado para esto, y no hay garantía de que su código se ejecutará después de que se devuelva la respuesta. ASP.NET hará todo lo posible para que se ejecute, pero no puede garantizarlo.
Entonces, esta es una buena solución para algo simple como lanzar un evento en un registro donde realmente no importa si pierde algunos aquí y allá. No es una buena solución para ningún tipo de operaciones comerciales críticas. En esas situaciones, debe adoptar una arquitectura más compleja, con una forma persistente de guardar las operaciones (por ejemplo, Azure Queues, MSMQ) y un proceso en segundo plano separado (por ejemplo, Azure Worker Role, Win32 Service) para procesarlas.
fuente
var _ = MyAsyncMethod();
con_ = MyAsyncMethod();
. Esto todavía evita la advertencia CS4014, pero hace que sea un poco más explícito que no está utilizando la variable.La respuesta de Peter Ritchie fue lo que quería, y el artículo de Stephen Cleary sobre el regreso temprano en ASP.NET fue muy útil.
Sin embargo, como un problema más general (no específico de un contexto ASP.NET), la siguiente aplicación de consola muestra el uso y el comportamiento de la respuesta de Peter usando
Task.ContinueWith(...)
GetStringData()
regresa temprano sin esperarMyAsyncMethod()
y las excepciones incluidasMyAsyncMethod()
se tratan enOnMyAsyncMethodFailed(Task task)
y no entry
/catch
alrededorGetStringData()
fuente
Console.ReadLine();
y agregue un poco de suspensión / retrasoMyAsyncMethod
y nunca verá la excepción.Termino con esta solución:
fuente
Esto se llama disparar y olvidar, y hay una extensión para eso.
Instalar paquete nuget .
Utilizar:
fuente
Supongo que surge la pregunta, ¿por qué necesitarías hacer esto? La razón
async
en C # 5.0 es para que pueda esperar un resultado. Este método no es realmente asíncrono, sino que simplemente se llama a la vez para no interferir demasiado con el hilo actual.Quizás sea mejor comenzar un hilo y dejar que termine solo.
fuente
async
es un poco más que simplemente "esperar" un resultado. "esperar" implica que las líneas que siguen a "esperar" se ejecutan de forma asíncrona en el mismo hilo que invocó "esperar". Esto se puede hacer sin "esperar", por supuesto, pero terminas teniendo un montón de delegados y pierdes el aspecto secuencial del código (así como la capacidad de usarusing
ytry/catch
...await
palabra clave y no use laasync
palabra clave, pero no tiene sentido usar laasync
palabra clave sin usarla tambiénawait
en la definición de ese método.async
es un poco más que simplemente" esperar "un resultado". Laasync
palabra clave (usted dio a entender que es la palabra clave al encerrarla en backticks) no significa nada más que esperar el resultado. Es la asincronía, como los conceptos generales de CS, lo que significa más que solo esperar un resultado.async
crea una máquina de estado que gestiona cualquier espera dentro del método asíncrono. Si no hayawait
s dentro del método, todavía crea esa máquina de estados, pero el método no es asíncrono. Y si elasync
método regresavoid
, no hay nada que esperar. Entonces, es más que solo esperar un resultado.async
palabra clave. Todo lo que necesita hacer (y todo lo que realmente sucede al final con una máquina de estado en ese caso especial) es que el método se ejecuta sincrónicamente y luego se envuelve en una tarea completada. Supongo que técnicamente no solo eliminas la máquina de estado; quita la máquina de estado y luego llamaTask.FromResult
. Supuse que usted (y también los escritores del compilador) podrían agregar el apéndice por su cuenta.En tecnologías con bucles de mensajes (no estoy seguro si ASP es uno de ellos), puede bloquear el bucle y procesar los mensajes hasta que finalice la tarea, y usar ContinueWith para desbloquear el código:
Este enfoque es similar al bloqueo en ShowDialog y sigue manteniendo la interfaz de usuario receptiva.
fuente
Llego tarde a la fiesta aquí, pero hay una biblioteca increíble que he estado usando y que no he visto referenciada en las otras respuestas
https://github.com/brminnick/AsyncAwaitBestPractices
Si necesita "disparar y olvidar", llame al método de extensión en la tarea.
Pasar la acción onException a la llamada asegura que obtenga lo mejor de ambos mundos, sin necesidad de esperar la ejecución y ralentizar a sus usuarios, al tiempo que conserva la capacidad de manejar la excepción de manera elegante.
En su ejemplo, lo usaría así:
También proporciona los AsyncCommands esperados que implementan ICommand de fábrica, lo que es excelente para mi solución MVVM Xamarin
fuente
La solución es iniciar el HttpClient en otra tarea de ejecución sin contexto de sincronización:
fuente
Si realmente quieres hacer esto. Solo para abordar "Llamar a un método asincrónico en C # sin esperar", puede ejecutar el método asincrónico dentro de a
Task.Run
. Este enfoque esperará hasta elMyAsyncMethod
final.await
desenvuelve asincrónicamente laResult
tarea, mientras que solo usando Result se bloquearía hasta que la tarea se hubiera completado.fuente
Por lo general, el método asíncrono devuelve la clase de tarea. Si usa un
Wait()
método oResult
propiedad y el código arroja una excepción (el tipo de excepción se envuelve)AggregateException
, entonces debe consultarException.InnerException
para localizar la excepción correcta.Pero también es posible usarlo
.GetAwaiter().GetResult()
: también esperará la tarea asincrónica, pero no envolverá la excepción.Así que aquí hay un breve ejemplo:
Es posible que también desee poder devolver algunos parámetros de la función asincrónica, lo que se puede lograr al proporcionar una
Action<return type>
función asincrónica adicional , por ejemplo, así:Tenga en cuenta que los métodos asíncronos generalmente tienen
ASync
nombres de sufijos, solo para evitar la colisión entre funciones de sincronización con el mismo nombre. (Por ejemploFileStream.ReadAsync
): he actualizado los nombres de las funciones para seguir esta recomendación.fuente