Controladores asíncronos en ASP.NET MVC: ventajas reales / ¿Cómo se logra?

12

He estado trabajando en un artículo sobre métodos de controlador asíncrono en ASP.NET MVC ( http://visualstudiomagazine.com/articles/2013/07/23/async-actions-in-aspnet-mvc-4.aspx ) y creo Puedo estar perdiendo el punto.

Considere este método que escribí, que es muy similar a un ejemplo del artículo:

[HttpGet]
[AsyncTimeout(8000)]
[HandleError(ExceptionType = typeof(TimeoutException), View = "TimedOut")]
public async Task<ActionResult> Index(CancellationToken cancellationToken)
{
    WidgetPageViewModel model = new WidgetPageViewModel()
    {
        toAdd = new Widget()
    };
    model.all = await _repo.GetAllAsync(cancellationToken);
    return View(model);
}

Según tengo entendido, así es como se desarrollarán las cosas en tiempo de ejecución:

  1. Se creará un hilo ASP.NET para una solicitud HTTP entrante.

  2. Este hilo (presumiblemente ha realizado algunos trabajos preliminares necesarios) ingresará a mi método Index () anterior.

  3. La ejecución alcanzará la palabra clave "esperar" y comenzará un proceso de adquisición de datos en otro hilo.

  4. El subproceso original "ASP.NET" volverá al código que llamó a mi método de controlador, con una instancia de clase Tarea como valor de retorno.

  5. El código de infraestructura que llamó a mi método de controlador continuará operando en el subproceso original "ASP.NET", hasta que llegue a un punto en el que necesite usar el objeto ActionResult real (por ejemplo, para representar la página).

  6. La persona que llama accederá a este objeto utilizando el miembro Task.Result, lo que hará que (es decir, el hilo "ASP.NET") espere el hilo creado implícitamente en el paso 3 anterior.

No veo lo que esto logra en comparación con lo mismo sin esperar / asíncrono, excepto por dos cosas que percibo como insignificantes:

  • El subproceso de la persona que llama y el subproceso de trabajo creado por await pueden funcionar en paralelo durante un período de tiempo (la parte "hasta" del n. ° 5 anterior). Mi presentimiento es que ese período de tiempo es bastante pequeño. Cuando la infraestructura llama a un método de controlador, creo que generalmente necesita el ActionResult real de la llamada del controlador antes de que pueda hacer mucho (si es que hay algo) más.

  • Existe una nueva infraestructura útil relacionada con el tiempo de espera y la cancelación de operaciones asíncronas de controlador de larga duración.

El propósito de agregar métodos de controlador asíncrono supuestamente es liberar esos hilos de trabajo ASP.NET para responder realmente las solicitudes HTTP. Estos hilos son un recurso finito. Desafortunadamente, no veo cómo el patrón sugerido en el artículo realmente sirve para conservar estos hilos. E incluso si lo hace, y de alguna manera descarga la carga de manejar la solicitud a algún hilo que no sea ASP.NET, ¿qué logra eso? ¿Los hilos que son capaces de manejar una solicitud HTTP son muy diferentes de los hilos en general?

usuario1172763
fuente
Execution will reach the "await" keyword and kick off a data acquisition process on another thread-- No necesariamente. asyncno requiere otro hilo ... Es una continuación. Se puede lograr reordenando las instrucciones en el mismo hilo.
Robert Harvey
Más información aquí: msdn.microsoft.com/en-us/library/hh191443.aspx
Robert Harvey
"La ejecución alcanzará la palabra clave de espera y dará inicio a un proceso de adquisición de datos en otro hilo". tienes esto al revés: la espera es cuando vuelve. Intente dividirlo para guardar el resultado de GetAllAsync () en una variable y espere eso y vea si se vuelve más claro.
Esben Skov Pedersen

Respuestas:

9

ASP.Net que no usa la Biblioteca Paralela de Tareas (TPL) está limitada en el número de solicitudes que puede manejar simultáneamente por el número de subprocesos en un grupo de subprocesos. ASP.Net que usa el TPL está limitado por la CPU / memoria / IO de las solicitudes de manejo de la máquina.

La biblioteca paralela de tareas (TPL) no consume subprocesos de la forma en que parece pensar que lo hace. Las tareas no son hilos, son una envoltura alrededor de alguna unidad de cálculo. El programador de tareas es responsable de ejecutar cada tarea en cualquier subproceso que no esté ocupado. En tiempo de ejecución, la espera de una tarea no bloquea el subproceso, simplemente aparca el estado de ejecución para que pueda continuar en un momento posterior.

Normalmente, una sola solicitud HTTP sería manejada por un solo subproceso, eliminando por completo ese subproceso del grupo hasta que se devuelva una respuesta. Con el TPL, no está obligado por esta restricción. Cualquier solicitud que ingrese comienza una continuación con cada unidad de cálculo requerida para calcular una respuesta capaz de ejecutarse en cualquier subproceso del grupo. Con este modelo, puede manejar muchas más solicitudes simultáneas que con ASP.Net estándar.

mortalapeman
fuente
Entonces, ¿cuándo se devuelve el subproceso ASP.NET al grupo? Cuando se golpea la palabra clave "aguardar"?
user1172763
async / await + TPL le permite al compilador dividir su código en unidades computacionales independientes que son ejecutadas por el programador de tareas. Un subproceso se devuelve conceptualmente al grupo cuando el programador de tareas no tiene más tareas que se puedan ejecutar y el subproceso finaliza el trabajo que se le ha asignado.
mortalapeman
Esto es conceptualmente correcto y probablemente una respuesta útil ... sin embargo, la realidad es un poco más complicada debido a la agilidad del hilo .
John Wu