2012-04-09 8 views
18

Servlet API dice acerca de "AsyncContext.start":¿Cuál es el propósito de AsyncContext.start (...) en Servlet 3.0?

vacío inicio (pista java.lang.Runnable)

Hace que el recipiente para despachar un hilo, posiblemente de un grupo de subprocesos administrado, para ejecutar el especificado Runnable. El contenedor puede propagar información contextual apropiada a Runnable.

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 ejemplo de servlet 3.0 características asincrónicos, donde utiliza AsyncContext.start, voy a mostrar la 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 ejemplos que he se reunió, el método de servicio solo almacena el AsyncContext en algún lugar 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(...)?

+0

¡Me estaba preguntando lo mismo! – Deadron

Respuesta

14

Has encontrado un mal ejemplo, en mi humilde opinión. De hecho, ni siquiera estaba al tanto de la existencia 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, p. cuando exactamente un subproceso espera datos que se supone que se transmitirán a varios clientes. También vea The Limited Usefulness of AsyncContext.start()

+0

Eso es lo que sospechaba. ¡Gracias! – Aivar

+0

¿Has descubierto algún cambio en esta implementación desde que respondiste? –

10

Tuve la misma reacción al principio - si solo está pasando el trabajo a otro hilo, ¿qué gana? La especificación no es de mucha ayuda para explicar por qué esta es una buena idea. Pero this post 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, puede 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 sucedió algo.

0

Una razón por la que esto puede ser útil es cuando desea liberar el hilo entrante, hacer otro trabajo y, una vez hecho esto, volver al hilo web (podría ser otro hilo, pero aún del grupo de servidores web) para completar la operación original 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 */ }); 

Se podría, por supuesto, enviar la respuesta en el hilo no servlet, pero esto tiene una desventaja - se utiliza hilo no servlet para hacer operaciones de servlet-típica, lo que significa está implícitamente cambiando el equilibrio entre la cantidad de potencia de hilo reservada para el trabajo de servlet frente a 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().

Cuestiones relacionadas