2011-09-02 22 views
12

Me pregunto cómo Tomcat 7 implementa el procesamiento asincrónico. Entiendo que el hilo de solicitud vuelve inmediatamente, permitiendo que el hilo de solicitud escuche inmediatamente una nueva solicitud y responda a ella.Tomcat 7 Async Processing

¿Cómo se maneja la solicitud 'async'? ¿Existe un grupo de subprocesos independiente que maneje las solicitudes asincrónicas? Supongo que bloquear IO se maneja usando algo como java.nio.Selector para el rendimiento. ¿Qué ocurre con los hilos que bloquean los cálculos de la CPU?

+0

Es posible que desee echar un vistazo a esto: http://stackoverflow.com/questions/ 7749350/illegalstateexception-not-supported-on-asynccontext-startasyncreq-res si desea implementar el procesamiento asincrónico en Tomcat 7. Hay un giro. – JVerstry

Respuesta

37

Está mezclando diferentes conceptos. Debe distinguir entre:

  1. asíncrono solicitud de entrega de acuerdo con Servlet 3.0; una API que le permite desacoplar una solicitud de servlet entrante del grupo de subprocesos de contenedor web. No crea ningún hilo sobre la marcha. El usuario de la interfaz debe implementar una solución de múltiples subprocesos adecuada. No se relaciona con IO sin bloqueo.
  2. Grupo de subprocesos; proporciona un mecanismo para obtener y administrar hilos en un contenedor web. Cuando se trata de solicitud asincrónica entregando tiene 2 opciones. Puede definir su propio ExecutorService y usarlo para seguir procesando la solicitud o puede crear un nuevo Runnable y enviarlo al AsyncContext obtenido llamando al AsyncContext.start(). En el caso de Tomcat, el último enfoque utiliza el grupo de subprocesos de Tomcat definido en server.xml.
  3. IO sin bloqueo (NIO); Aunque es asincrónico también es una historia diferente. Se refiere a operaciones IO sin bloqueo, como disco o red IO. Si desea habilitar NIO para el procesamiento de solicitud HTTP, eche un vistazo a Tomcat's documentation.

El ejemplo a continuación describe cómo se puede trabajo. Utiliza solo un hilo para trabajos de trabajadores. Si se ejecuta desde 2 navegadores diferentes en paralelo la salida tiene este aspecto (utilizo un registrador de encargo):

DATE       THREAD_ID LEVEL  MESSAGE 
2011-09-03 11:51:22.198 +0200  26  I:  >doGet: chrome 
2011-09-03 11:51:22.204 +0200  26  I:  <doGet: chrome 
2011-09-03 11:51:22.204 +0200  28  I:  >run: chrome 
2011-09-03 11:51:27.908 +0200  29  I:  >doGet: firefox 
2011-09-03 11:51:27.908 +0200  29  I:  <doGet: firefox 
2011-09-03 11:51:32.227 +0200  28  I:  <run: chrome 
2011-09-03 11:51:32.228 +0200  28  I:  >run: firefox 
2011-09-03 11:51:42.244 +0200  28  I:  <run: firefox 

Usted ve que los métodos doGet terminan inmediatamente, mientras que el trabajador todavía funciona. Las 2 solicitudes de prueba: http://localhost:8080/pc/TestServlet?name=chrome y http://localhost:8080/pc/TestServlet?name=firefox.

ejemplo simple servlet

@WebServlet(asyncSupported = true, value = "/TestServlet", loadOnStartup = 1) 
public class TestServlet extends HttpServlet { 
    private static final Logger LOG = Logger.getLogger(TestServlet.class.getName()); 
    private static final long serialVersionUID = 1L; 
    private static final int NUM_WORKER_THREADS = 1; 

    private ExecutorService executor = null; 

    @Override 
    public void init() throws ServletException { 
     this.executor = Executors.newFixedThreadPool(NUM_WORKER_THREADS); 
    } 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

     final String name = request.getParameter("name"); 
     LOG.info(">doGet: " + name); 

     AsyncContext ac = request.startAsync(); // obtain async context 
     ac.setTimeout(0); // test only, no timeout 

     /* Create a worker */ 
     Runnable worker = new TestWorker(name, ac); 

     /* use your own executor service to execute a worker thread (TestWorker) */ 
     this.executorService.execute(worker); 

     /* OR delegate to the container */ 
     // ac.start(worker); 

     LOG.info("<doGet: " + name); 
    } 
} 

... y el TestWorker

public class TestWorker implements Runnable { 
    private static final Logger LOG = Logger.getLogger(TestWorker.class.getName()); 
    private final String name; 
    private final AsyncContext context; 
    private final Date queued; 

    public TestWorker(String name, AsyncContext context) { 
     this.name = name; 
     this.context = context; 
     this.queued = new Date(System.currentTimeMillis()); 
    } 

    @Override 
    public void run() { 

     LOG.info(">run: " + name); 

     /* do some work for 10 sec */ 
     for (int i = 0; i < 100; i++) { 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       throw new RuntimeException(e); 
      } 
     } 

     ServletResponse response = this.context.getResponse(); 
     response.setContentType("text/plain"); 

     try { 
      PrintWriter out = response.getWriter(); 
      out.println("Name:\t\t" + this.name); 
      out.println("Queued:\t\t" + this.queued); 
      out.println("End:\t\t" + new Date(System.currentTimeMillis())); 
      out.println("Thread:\t\t" + Thread.currentThread().getId()); 
      out.flush(); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 

     this.context.complete(); 

     LOG.info("<run: " + name); 
    } 
} 
+0

Gracias por la aclaración. Con respecto a CometProcessor API, ¿hay un hilo que esté sondeando todas las conexiones actuales para ver cuál tiene "datos disponibles para leer"? Para ser específico, ¿cuál sería el número esperado de hilos cuando hay 10 solicitudes frente a 100? Suponiendo que estas son solicitudes que han recibido el evento BEGIN pero que no han recibido el evento LEER. http://tomcat.apache.org/tomcat-7.0-doc/aio.html –

+0

@John Si está satisfecho con la respuesta de su hogar, debe aprobarla.Su pregunta adicional debe hacerse una nueva pregunta (eventualmente, puede hacer una referencia a esta). – JVerstry

+0

HI @JVerstry, para ser sincero, no me siento completamente satisfecho con la respuesta. Todavía no siento que tenga una buena comprensión de la arquitectura de Tomcat para el "procesamiento asíncrono". –