Estoy intentando hacer uso de la async/await
función de ASP.NET en mi proyecto de API web. No estoy muy seguro de si hará alguna diferencia en el rendimiento de mi servicio API web. A continuación, encontrará el flujo de trabajo y el código de muestra de mi aplicación.
Flujo de trabajo:
Aplicación de interfaz de usuario → Punto final de la API web (controlador) → Método de llamada en la capa de servicio de la API web → Llamar a otro servicio web externo. (Aquí tenemos las interacciones DB, etc.)
Controlador:
public async Task<IHttpActionResult> GetCountries()
{
var allCountrys = await CountryDataService.ReturnAllCountries();
if (allCountrys.Success)
{
return Ok(allCountrys.Domain);
}
return InternalServerError();
}
Capa de servicio:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
Probé el código anterior y está funcionando. Pero no estoy seguro de si es el uso correcto de async/await
. Por favor comparta sus pensamientos.
Respuestas:
Tenga en cuenta que el principal beneficio del código asincrónico en el lado del servidor es la escalabilidad . No hará mágicamente que sus solicitudes se ejecuten más rápido. Cubro varias consideraciones de "debería usar
async
" en mi artículo sobreasync
ASP.NET .Creo que su caso de uso (llamar a otras API) es adecuado para el código asincrónico, solo tenga en cuenta que "asincrónico" no significa "más rápido". El mejor enfoque es primero hacer que su interfaz de usuario sea receptiva y asincrónica; esto hará que su aplicación se sienta más rápida incluso si es un poco más lenta.
En lo que respecta al código, esto no es asincrónico:
Necesitaría una implementación verdaderamente asincrónica para obtener los beneficios de escalabilidad de
async
:O (si su lógica en este método realmente es solo una transferencia):
Tenga en cuenta que es más fácil trabajar "de adentro hacia afuera" en lugar de "de afuera hacia adentro" de esta manera. En otras palabras, no empiece con una acción de controlador asíncrono y luego fuerce los métodos posteriores a ser asíncronos. En su lugar, identifique las operaciones naturalmente asincrónicas (llamadas a API externas, consultas de bases de datos, etc.) y conviértalas en asincrónicas en el nivel más bajo primero (
Service.ProcessAsync
). Luego, deje queasync
fluya, haciendo que las acciones de su controlador sean asincrónicas como último paso.Y bajo ninguna circunstancia debe utilizar
Task.Run
en este escenario.fuente
Es correcto, pero quizás no sea útil.
Como no hay nada que esperar, no hay llamadas a las API de bloqueo que podrían operar de forma asincrónica, entonces está configurando estructuras para rastrear la operación asincrónica (que tiene una sobrecarga) pero luego no hace uso de esa capacidad.
Por ejemplo, si la capa de servicio estaba realizando operaciones de base de datos con Entity Framework, que admite llamadas asincrónicas:
Permitiría que el hilo de trabajo haga otra cosa mientras se consulta la base de datos (y, por lo tanto, puede procesar otra solicitud).
Await tiende a ser algo que debe reducirse hasta el final: es muy difícil adaptarse a un sistema existente.
fuente
No está aprovechando async / await de manera efectiva porque el hilo de solicitud se bloqueará mientras se ejecuta el método sincrónico
ReturnAllCountries()
El hilo que está asignado para manejar una solicitud estará esperando inactivo mientras
ReturnAllCountries()
funciona.Si puede implementar
ReturnAllCountries()
para ser asíncrono, verá beneficios de escalabilidad. Esto se debe a que el subproceso podría liberarse de nuevo al grupo de subprocesos .NET para manejar otra solicitud, mientrasReturnAllCountries()
se ejecuta. Esto permitiría que su servicio tuviera un mayor rendimiento al utilizar subprocesos de manera más eficiente.fuente
Cambiaría su capa de servicio a:
tal como lo tiene, todavía está ejecutando su
_service.Process
llamada sincrónicamente y obteniendo muy poco o ningún beneficio al esperarla.Con este enfoque, envuelve la llamada potencialmente lenta en a
Task
, la inicia y la devuelve para que la espere. Ahora obtiene el beneficio de esperar elTask
.fuente
Service
no es un método asíncrono y no se está esperando dentro de laService
propia llamada. Puedo entender su punto, pero no creo que se aplique aquí.Task.Run
debe evitarse en ASP.NET. Este enfoque eliminaría todos los beneficios deasync
/await
y en realidad funcionaría peor bajo carga que solo una llamada síncrona.