Encontré algunas de las mejores prácticas para la programación asincrónica usando c # 's async
/ await
keywords (soy nuevo en c # 5.0).
Uno de los consejos dados fue el siguiente:
Estabilidad: conozca sus contextos de sincronización
... Algunos contextos de sincronización son no reentrantes y de un solo subproceso. Esto significa que solo se puede ejecutar una unidad de trabajo en el contexto en un momento dado. Un ejemplo de esto es el subproceso de la interfaz de usuario de Windows o el contexto de solicitud ASP.NET. En estos contextos de sincronización de un solo subproceso, es fácil bloquearse. Si genera una tarea desde un contexto de un solo subproceso, luego espera esa tarea en el contexto, su código de espera puede estar bloqueando la tarea en segundo plano.
public ActionResult ActionAsync()
{
// DEADLOCK: this blocks on the async task
var data = GetDataAsync().Result;
return View(data);
}
private async Task<string> GetDataAsync()
{
// a very simple async method
var result = await MyWebService.GetDataAsync();
return result.ToString();
}
Si trato de analizarlo yo mismo, el hilo principal genera uno nuevo en MyWebService.GetDataAsync();
, pero como el hilo principal espera allí, espera el resultado en GetDataAsync().Result
. Mientras tanto, digamos que los datos están listos. ¿Por qué el hilo principal no continúa su lógica de continuación y devuelve un resultado de cadena GetDataAsync()
?
¿Puede alguien explicarme por qué hay un punto muerto en el ejemplo anterior? No tengo ni idea de cuál es el problema ...
fuente
var data = GetDataAsync().Result;
hay una línea de código que nunca debe hacerse en un contexto que no debe bloquear (solicitud de interfaz de usuario o ASP.NET). Incluso si no se bloquea, está bloqueando el hilo por un período de tiempo indeterminado. Así que básicamente es un ejemplo terrible. [Debe salir del hilo de la interfaz de usuario antes de ejecutar un código como ese, o usarloawait
allí también, como sugiere Toni.]Respuestas:
Eche un vistazo a este ejemplo , Stephen tiene una respuesta clara para usted:
Otro enlace que debería leer: ¡ Espera, interfaz de usuario y puntos muertos! ¡Oh mi!
fuente
GetDataAsync().Result;
se ejecutará cuando la tarea devuelta por seGetDataAsync()
complete, mientras tanto, bloquea el hilo de la interfaz de usuarioreturn result.ToString()
) se pone en cola en el hilo de la interfaz de usuario para su ejecuciónGetDataAsync()
se completará cuando se ejecute su continuación en cola¡Punto muerto!
El punto muerto se puede romper con las alternativas proporcionadas para evitar el Hecho 1 o el Hecho 2.
var data = await GetDataAsync()
, que permite que el subproceso de la interfaz de usuario siga ejecutándosevar data = Task.Run(GetDataAsync).Result
, use , que publicará la continuación en el contexto de sincronización de un subproceso de grupo de subprocesos. Esto permiteGetDataAsync()
que se complete la tarea devuelta por .Esto se explica muy bien en un artículo de Stephen Toub , aproximadamente a la mitad de donde usa el ejemplo de
DelayAsync()
.fuente
var data = Task.Run(GetDataAsync).Result
eso, eso es nuevo para mí. Siempre pensé que el exterior.Result
estará disponible tan pronto comoGetDataAsync
llegue la primera espera , asídata
que siempre lo estarádefault
. Interesante.Estaba jugando con este problema nuevamente en un proyecto ASP.NET MVC. Cuando desee llamar a
async
métodos desde aPartialView
, no puede realizar elPartialView
async
. Obtendrá una excepción si lo hace.Puede utilizar la siguiente solución alternativa sencilla en el escenario en el que desea llamar a un
async
método desde un método de sincronización:SynchronizationContext
SynchronizationContext
Ejemplo:
fuente
Otro punto principal es que no debe bloquear las Tareas y usar async hasta el final para evitar interbloqueos. Entonces todo será bloqueo asíncrono, no síncrono.
fuente
Una solución que encontré es usar un
Join
método de extensión en la tarea antes de pedir el resultado.El código se ve así:
Donde el método de unión es:
No estoy lo suficientemente interesado en el dominio para ver los inconvenientes de esta solución (si corresponde)
fuente