servlets servlet-3.0

servlets - ¿Cuál es el propósito de AsyncContext.start(...) en Servlet 3.0?



servlet-3.0 (4)

La API de Servlet dice acerca de "AsyncContext.start":

void start (java.lang.Runnable run)

Hace que el contenedor envíe un hilo, posiblemente desde un grupo de subprocesos administrados, para ejecutar Runnable especificado. El contenedor puede propagar información contextual apropiada a Runnable.

A partir de esta descripción, no está claro cómo se relaciona con la tarea de optimizar el uso de subprocesos cuando el trabajo requiere una espera.

En "Servlet & JSP", Budi Kurniawan da un ejemplo de características asíncronas de Servlet 3.0, donde usa AsyncContext.start , mostraré una versión simplificada del ejemplo:

public void doGet(...) { final AsyncContext asyncContext = request.startAsync(); asyncContext.start(new Runnable() {                         @ Override public void run() { // do some work here which involves waiting ... asyncContext.complete(); } }); }

En la mayoría de los otros ejemplos que he conocido, el método de servicio simplemente almacena el AsyncContext en alguna parte y se procesa en otro lugar (por ejemplo, mediante un hilo de fondo). En este ejemplo, parece que el trabajo acaba de pasar a otro hilo, que completa la solicitud. Según tengo entendido, ahora es simplemente el hilo de trabajo, que desperdicia tiempo en esperar.

¿De verdad ganas algo pasando el trabajo (que implica esperar) de un hilo a otro? Si no, ¿cuál es el propósito de AsyncContext.start(...) ?


Al principio tuve la misma reacción: si solo pasas el trabajo a otro hilo, ¿qué ganas? La especificación no es de mucha ayuda para explicar por qué esta es una buena idea. Pero esta publicación hace un excelente trabajo. Básicamente, es para permitir que el servidor se degrade elegantemente bajo una gran carga en lugar de simplemente fallar al quedarse sin hilos. El trabajo real se realiza en un conjunto de hilos de tamaño fijo, por lo que el servidor puede aceptar cualquier cantidad de solicitudes sin tener que mantener un hilo para cada una hasta que se complete. Por supuesto, es posible que deba modificar sus configuraciones de O / S para poder mantener abiertos miles de sockets a la vez.

Una vez que tenga esta capacidad, podrá aprovechar más fácilmente la arquitectura Comet (servidor push), donde el cliente Javascript mantiene abierta una solicitud AJAX para que el servidor pueda notificarlo tan pronto como ocurra algún evento, en lugar de tener que sondear el servidor para averiguar si algo sucedió


Una razón por la que esto puede ser útil es cuando desea liberar el hilo web entrante, hacer otro trabajo y, una vez hecho esto, volver al hilo web (puede ser otro hilo, pero aún del grupo del servidor web) para completar el original operación y enviar respuesta al cliente.

Por ejemplo:

1. ac = request.startAsync(); 2. forward("some data", "another system"); // async outbound HTTP request 3. (at this point, incoming servlet thread is released to handle other requests) 4. (in some other, non-servlet thread, upon "forward" response arrival) ac.start(new Runnable() { /* send response to the client */ });

Por supuesto, puede enviar una respuesta en el subproceso que no es de servlet, pero esto tiene una desventaja: utiliza subprocesos no servlet para realizar operaciones típicas de servlet, lo que significa que está cambiando implícitamente el equilibrio entre la cantidad de potencia de subprocesos reservada para trabajo servlet vs. otro trabajo.

En otras palabras, le da la posibilidad de publicar Runnable en el grupo de subprocesos de servlet. Obviamente, estas son necesidades raras, pero aún así, da algún razonamiento para el método AsyncContext.start ().


Encontraste un pobre ejemplo, en mi humilde opinión. De hecho, ni siquiera estaba al tanto de la AsyncContext.start() de AsyncContext.start() .

Eché un vistazo rápido a cómo Jetty y Tomcat implementan esto. De hecho, parecen tener algún grupo de subprocesos que maneja invocaciones asincrónicas de forma independiente.

Tal uso de la API no le da nada o muy poco. En lugar de bloquear el hilo HTTP, está bloqueando otro grupo de subprocesos. Así que me puedo imaginar que la aplicación aún acepta nuevas conexiones, pero el problema persiste: el contenedor no puede manejarlas todas porque ese grupo de subprocesos adicionales aún es limitado.

La totalidad de los puntos de AsyncContext es la capacidad de manejar más de una solicitud por un solo hilo. A menudo, solo necesita un único hilo para manejar miles de conexiones asíncronas, por ejemplo, cuando exactamente un subproceso espera datos que se supone que se emitirán a varios clientes. Consulte también La utilidad limitada de AsyncContext.start ()