Este artículo proviene de un motor de traducción automática.

Tecnología de vanguardia

Nueva visita a las páginas de ASP.NET asincrónico

Dino Esposito

ASP.NET ha admitido siempre controladores HTTP sincrónicos y asincrónicos. Ahora, ASP.NET 2.0 tiene nuevas características para que sea más fácil y más rápido a los desarrolladores crear las páginas asincrónicas. Especialmente para aplicaciones basadas en servidor, las operaciones asincrónicas son fundamentales para habilitar la escalabilidad. Si descubre que necesita escalar la aplicación Web existente, el primer aspecto que hay que tener en cuenta es cuánto asynchrony puede agregar a las páginas.

En este sentido, ASP.NET se comporta como cualquier otra aplicación de servidor que realiza algunas tareas en segundo plano en nombre de varios clientes. Cada solicitud entrante se asigna a un subproceso pertenecientes a ASP.NET que se ha seleccionado en el grupo de subprocesos de ASP.NET. El subproceso permanece bloqueado hasta que la operación ha finalizado y se ha generado alguna respuesta para el cliente. ¿Cuánto tiempo debe esperar el subproceso El entorno de tiempo de ejecución ASP.NET puede configurarse para definir un tiempo de espera personalizado (90 segundos es el valor predeterminado), pero es más importante evitar que el subproceso bloqueado.

Al tratar las operaciones potencialmente largas, el tiempo de espera como máximo sólo garantiza que después de un número determinado de segundos, el subproceso se se liberan y devuelve al grupo. En su lugar, lo que desea es evitar que el subproceso bloqueado durante un largo período de tiempo. Lo ideal sería que desea que el subproceso para empezar a una solicitud y, a continuación, dar prioridad a otro subproceso de que no sean ASP.NET. El mismo subproceso o la otra de la agrupación ASP.NET, se recogen nuevo una vez finalizada la operación para enviar la respuesta al cliente. Este paradigma se conoce como las páginas asincrónicas de ASP.NET.

Cuando se trata de operaciones asincrónicas, debe distinguir entre las páginas que se encuentran asincrónicas con respecto al usuario y las páginas que se encuentran asincrónicas con respecto al motor en tiempo de ejecución de ASP.NET. Para las páginas asincrónicas con respecto al usuario, el enfoque sólo viable es una operación de AJAX. Sin embargo, el uso de AJAX para realizar una operación potencialmente lenta disminuye el impacto sobre el usuario final pero no poner ningún desahogo al motor en tiempo de ejecución 
ASP.NET.

Páginas asincrónicas y el tiempo de ejecución de ASP.NET

Cuanto más tiempo el subproceso se bloquea en la solicitud, más tiempo un subproceso se resta de la agrupación ASP.NET para atender nuevas solicitudes entrantes. Cuando no hay subprocesos disponibles para atender nuevas solicitudes, las peticiones son puestas en la cola. Esto puede provocar retrasos y degradación del rendimiento general.

En ASP.NET, los controladores HTTP son sincrónicos de forma predeterminada. Controladores HTTP asincrónicos deben ser una arquitectura y implementados por aplicar ligeramente distintas interfaces explícitamente. Un controlador sincrónico difiere de un controlador asincrónico en uno de los aspectos clave: en lugar del método ProcessRequest sincrónico, un controlador asincrónico utiliza los métodos enumerados a continuación, que forman parte de la interfaz de IHttpAsyncHandler:

IAsyncResult BeginProcessRequest(

     HttpContext context, 

     AsyncCallback cb, 

     object extraData);


void EndProcessRequest(
     

     IAsyncResult result);

BeginProcessRequest contiene la operación a ejecutarse para atender la solicitud. Este código debe diseñarse para iniciar la operación en un subproceso secundario y devolver inmediatamente. EndProcessRequest contiene el código para completar la solicitud se inició anteriormente.

Como puede ver, una solicitud asincrónica de HTTP se divide en dos partes: antes y después del punto de async “ ”, la etapa del ciclo de vida de la solicitud donde se cambia el subproceso que posee la solicitud. Cuando se alcanza el punto asincrónico, el subproceso original se ASP.NET produce control a otro subproceso. Esta operación potencialmente larga tiene lugar en entre las dos partes de la solicitud ASP.NET. Cada parte de la solicitud asincrónica se ejecuta independientemente de la otra, sin afinidad lo que respecta a los subprocesos. En otras palabras, no hay ninguna garantía de que el mismo subproceso se ocupará de las dos partes de la solicitud. El efecto neto es que no hay subprocesos se bloquean durante el tiempo que dure la operación.

En este momento, la pregunta obvia es: ¿subproceso que realmente se encarga de la operación “ larga ”? ASP.NET utiliza puertos de finalización de E/s internamente para realizar un seguimiento de la terminación de una solicitud. Cuando se alcanza el punto asincrónico, ASP.NET enlaza la petición pendiente con un puerto de finalización de E/s y registra una devolución de llamada para recibir una notificación cuando ha terminado la solicitud. El sistema operativo utilizará uno de sus propios subprocesos dedicados para supervisar la terminación de la operación, lo que libera de tener que esperar en completo inactivo el subproceso de ASP.NET. Cuando termina la operación, el sistema operativo coloca un mensaje en la cola de finalización, que desencadena la devolución de llamada ASP.NET, a continuación, recogerá uno de sus propios subprocesos para reanudar la solicitud. Como se mencionó, puertos de finalización de E/s son una característica del sistema operativo.

La naturaleza real de las páginas asincrónicas

En ASP.NET, las páginas asincrónicas son suelen estar asociadas a la idea de mejorar el rendimiento de una página determinada encargado de realizar una operación potencialmente larga. Sin embargo, algunos puntos adicionales deben tenerse en cuenta. Desde la perspectiva del usuario, las solicitudes sincrónicas y asincrónicas casi el mismo aspecto. Si se espera que la operación solicitada para tomar, por ejemplo, 30 segundos para finalizar, el usuario esperará al menos 30 segundos para volver a la nueva página. Esto ocurre independientemente de la implementación sincrónica o asincrónica de la página. Además, no se demasiado sorprenda si una página asincrónica termina tarda un poco más para completar una solicitud única. Entonces, ¿cuál es el beneficio de las páginas asincrónicas?

Escalabilidad no es bastante el mismo que el rendimiento. O bien, al menos, escalabilidad es acerca del rendimiento, pero en un nivel diferente: toda la aplicación en lugar de una única solicitud. La ventaja de que las páginas asincrónicas aportan a la tabla queda mucho menos trabajo para los subprocesos en el grupo ASP.NET. Esto no fabrica las solicitudes largas se ejecuten más rápidamente, pero resulta útil el sistema de atender solicitudes que no sean largas como de costumbre: es decir, con sin retrasos especiales derivados continuo ralentizar las solicitudes.

Las solicitudes asincrónicas aprovechar las ventajas de los controladores HTTP asincrónicos, que hayan sido siempre una característica de la plataforma de ASP.NET. Sin embargo, los formularios Web Forms de ASP.NET y ASP.NET MVC proporcionan sus propias instalaciones para simplificar a los desarrolladores implementar acciones de async. En el resto del artículo, trataré las operaciones asincrónicas en ASP.NET MVC 2.

Acciones de controlador asincrónico

En ASP.NET MVC 1.0, cualquier acción de controlador sólo se puede ejecutar sincrónicamente. Sin embargo, una nueva clase AsyncController se agregó a la biblioteca MVC Futures. Una vez que haya transcurrido un período experimental, async API para los controladores se agregó oficialmente al marco de trabajo de ASP.NET MVC y está totalmente disponible y documentada de la versión 2 de ASP.NET MVC framework. (La sintaxis y las características tratadas en este artículo hacen referencia a RC de ASP.NET MVC 2.)  Si reproduce un poco con la clase AsyncController en la biblioteca MVC Futures, observará algunos cambios y la API es más sencilla y clara.

El AsyncController sirve para garantizar que todos los métodos expuestos de la acción ejecutan asincrónicamente sin cambiar el enfoque general con respecto a la programación que caracteriza el marco de trabajo de ASP.NET MVC. El diagrama en La figura 1 muestra la secuencia de pasos tras el procesamiento de una acción asincrónica.

Figure 1 Mechanics of an Async Action Method in ASP.NET MVC
Figura 1 Mecánica de un método de acción de Async en ASP.NET MVC

El punto asincrónico se coloca entre la ejecución y ejecutaban sucesos. Cuando el invocador de acción notifica que se acerca de para ejecutar la acción, el subproceso que ejerzan todavía es el subproceso original de ASP.NET que recoge la solicitud a partir de la cola del servidor Web. En este momento, se ejecuta la acción. Al final cuando el invocador de acción está listo para notificar el evento ejecutado de acción, posiblemente otro subproceso ASP.NET está teniendo cuidado de la solicitud. Figura 2 muestra este escenario.


Figura 2 Cambio de una llamada de método asincrónicas acción de subprocesos

Antes de tratar los detalles de cómo crear y depurar los métodos asincrónicos, otro punto fundamental de las operaciones asincrónicas de ASP.NET debe quedar claro: No todas las acciones son buenos candidatos para convertirse en las operaciones asincrónicas.

El destino real de las operaciones asincrónicas

Sólo las operaciones dependientes de E/S son buenos candidatos para convertirse en los métodos de acción de asincrónica de una clase de controlador asincrónico. Una operación dependiente de E/S es una operación que no depende de la CPU local para su finalización. Cuando una operación dependiente de E/S está activa, la CPU sólo espera datos que se va a procesar (es decir, descargó) desde el almacenamiento de información externa (una base de datos o un servicio remoto). Las operaciones de dependiente de E/S son en contraste con operaciones de CPU enlazadas, donde la realización de una tarea depende de la actividad de la CPU.

Un ejemplo típico de una operación dependiente de E/S es la invocación de un servicio remoto. En este caso, los métodos de acción desencadenan la solicitud y simplemente esperan cualquier respuesta a descargarse. El trabajo real es realizado remotamente por otro equipo y otra CPU. Por lo tanto, el subproceso de ASP.NET está atascado en espera y estar inactivo. Liberación de que el subproceso inactivo del derecho de espera para atender otras solicitudes entrantes es la ganancia de rendimiento puede lograr con implementación asincrónica de acciones o las páginas.

Da la casualidad de que no todas las operaciones de larga duración le proporcionará una ventaja concreta si implementa de forma asincrónica. Un cálculo en memoria largo no beneficiarse significativamente de implementación asincrónica. Incluso podría ejecutar ligeramente más lento, porque la misma CPU es servir la solicitud ASP.NET y el cálculo. Además, todavía deberá un subproceso de ASP.NET para físicamente que se ocupe del cálculo. Hay pocas ventajas si lo hay, en utilizando la implementación asincrónica para operaciones enlazadas de CPU. Por otro lado, si intervienen los recursos remotos, incluso varios 
resources, mediante métodos de async realmente puede aumentar el rendimiento de la aplicación, si no es el rendimiento de la solicitud individual.

Volverá a este punto en breve con un ejemplo. Por ahora, let’s se centran en la sintaxis requerida para definir y ejecutar acciones asíncrona en ASP.NET MVC.

Reconocer las rutas de Async

¿En la que forma es una ruta de async diferente de una ruta sincrónica? En MVC Futures, se le pidió que utilizan métodos diferentes para registrar rutas sincrónicas y asincrónicas. Aquí es la manera antigua para registrar una ruta asincrónico:

routes.MapAsyncRoute(

    "Default",

    "{controller}/{action}/{id}",

    new { controller = "Home", action = "Index", id = "" }

);

Tenían que utilizar el método de extensión MapAsyncRoute en lugar de la estándar MapRoute desea utilizará para métodos sincrónicos clásicos. En ASP.NET MVC 2 RC, sin embargo, esta distinción se ha quitado. Ahora tiene sólo una manera de registrar sus rutas: el método MapRoute — independientemente de cómo, a continuación, se ejecutará la acción.

La dirección URL de la solicitud, por lo tanto, se procesa como de costumbre y averiguar el nombre de la clase de controlador para utilizar. De hecho, es necesario, que un método asincrónico está definido en una clase de controlador que se deriva de la clase AsyncController nueva, que se ilustra aquí:

public class TestController : AsyncController

{

  ...

}

Si se hereda la clase de controlador de AsyncController, la convención de asignación de nombres de acción a los métodos es un poco diferente. Una clase AsyncController puede servir las solicitudes sincrónicas y asincrónicas. Como resultado, la convención utilizada puede reconocer un método de ejecución y un método RunAsync, tal como se muestra aquí:

public class TestController : AsyncController

{

  public ActionResult Run(int id) 

  {

     ...

  }

  public void RunAsync(int id) 

  {

     ...

  }

}

Si hace esto, sin embargo, una excepción se producirá (consulte Figura 3).

Una acción asincrónica se identifica por su nombre y los patrones esperados es xxxAsync, donde xxx indica el nombre predeterminado de la acción que se va a ejecutar. Claramente, si existe otro método denominado xxx y eliminar la no se ambigüedad utilizando atributos, a continuación, se produce una excepción como en Figura 3.


Figura 3 Referencias ambiguas en el nombre de la acción

La palabra Async se considera un sufijo. La dirección URL para invocar el método RunAsync contendrá el prefijo ejecutar. Por ejemplo, la siguiente dirección URL invocará al método RunAsync, pasando un valor de 5 como un parámetro de ruta:

http://myserver/demo/run/5

Si esto se resolverá como una acción sincrónica o asincrónica depende de los métodos tienen en la clase AsyncController. Sin embargo, el método xxxAsync identifica sólo el desencadenador de la operación. El finalizador de la solicitud es otro método en la clase de controlador denominada xxxCompleted:

public ActionResult RunCompleted(DataContainer data)

{

    ...

}

Tenga en cuenta la firma diferente de los dos métodos que define la acción asincrónica. Se espera que el desencadenador sea un método void. Si define que devuelva cualquier valor, el valor devuelto simplemente se pasarán por alto. Los parámetros de entrada del método xxxAsync estará sujeto a modelo de enlace como de costumbre. El método finalizador devuelve un objeto ActionResult como de costumbre y recibe un objeto personalizado que contiene los datos que se espera para procesar y pasarlas al objeto de vista. Un protocolo especial es necesario para que coincidan con los valores calculados por el desencadenador a los parámetros declarados por el finalizador.

La clase AsyncController

La clase de controlador AsyncController hereda de controlador e implementa un montón de nuevas interfaces tal como se muestra aquí:

public abstract class AsyncController : Controller, 

                IAsyncManagerContainer, 

IAsyncController, IController

El aspecto más distintivo de un controlador asincrónico es el objeto invocador de acción especial que se emplea debajo del capó para realizar operaciones. Las necesidades de invocador un contador para realizar el seguimiento del número de operaciones individuales que componen la acción y se debe sincronizar antes de la acción general se puede declarar finalizado. Figura 4 proporciona una implementación de ejemplo para una acción asincrónica.

Figura 4 Un simple método de acción asincrónico

public void RunAsync(int id) 

{

    AsyncManager.OutstandingOperations.Increment();



    var d = new DataContainer();

     ...

            

    // Do some remote work (i.e., invoking a service)

     ...



    // Terminate operations

    AsyncManager.Parameters["data"] = d;

    AsyncManager.OutstandingOperations.Decrement();

}

public ActionResult RunCompleted(DataContainer data)

{

   ...

}

El miembro OutstandingOperations en la clase AsyncManager proporciona un contenedor que mantiene un recuento de las operaciones asincrónicas pendientes. Es una instancia de la clase auxiliar de OperationCounter y proporciona una API ad hoc para incremento y decremento. El método Increment no se limita a incrementos de unario, tal como se muestra aquí:

AsyncManager.OutstandingOperations.Increment(2);

service1.GetData(...);

AsyncManager.OutstandingOperations.Decrement();

service2.GetData(...);

AsyncManager.OutstandingOperations.Decrement();

Se utiliza el diccionario AsyncManager parámetros a los valores de grupo que para se van a pasar como argumentos al método finalizador de la llamada asincrónica. Se espera que el diccionario de parámetros contiene una entrada para cada parámetro que se va a pasar para el finalizador, el método xxxCompleted en el ejemplo anterior. Si no se puede encontrar una coincidencia entre las entradas de los nombres de parámetro y de diccionario, se asume un valor predeterminado para el parámetro — null para los tipos de referencia. No se provoca ninguna excepción, a menos que se intenta obtener acceso a un objeto null. El método xxxCompleted recibe parámetros de cualquier tipo compatible y utiliza para llenar la colección ViewData o cualquier objeto con tipo seguro reconocido por la vista. El método xxxCompleted es responsable de devolver un objeto ActionResult.

¿Una buena ajustar o no?

Ajustar hacia arriba, las solicitudes sincrónicas son una característica necesaria en ASP.NET y, de hecho, los controladores HTTP asincrónicos han sido admitidos desde ASP.NET 1.0.

Formularios Web Forms de ASP.NET y ASP.NET MVC ofrecen herramientas de nivel superiores a las operaciones de async de código, cada uno dentro de su propio modelo de aplicación: en ASP.NET MVC, hay controladores de async y en formularios Web Forms confían en páginas asincrónicas. 

No obstante, el aspecto clave de las acciones de async es decidir si una tarea determinada es un buen ajuste para una implementación asincrónica. Sólo se deben generar métodos Async alrededor de las operaciones dependientes de E/S. Y, por último, tenga en cuenta que async métodos no se ejecutarán más rápido a sí mismos, pero permitirá que otras solicitudes se ejecuten más rápidamente.

Dino Esposito es el autor del próximo libro “Programming ASP.NET MVC” de Microsoft Press y coautor de “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Con residencia en Italia, Esposito participa habitualmente en conferencias y eventos del sector en todo el mundo. Puede participar en su blog en weblogs.asp.net/despos.

Gracias al siguiente técnico experto para revisar este artículo: Stefan Schackow