2015-12-05 2 views
1

Ci-dessous le code sont servlet 3.1 Non Blocage IO demo:Questions sur Servlet 3.1 Non Les bloqueurs de IO Exemple

UploadServlet:

@WebServlet(name = "UploadServlet", urlPatterns = {"/UploadServlet"}, asyncSupported=true) 
public class UploadServlet extends HttpServlet { 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     AsyncContext context = request.startAsync(); 
     // set up async listener 
     context.addListener(new AsyncListener() { 
      public void onComplete(AsyncEvent event) throws IOException { 
       event.getSuppliedResponse().getOutputStream().print("Complete"); 

      } 

      public void onError(AsyncEvent event) { 
       System.out.println(event.getThrowable()); 
      } 

      public void onStartAsync(AsyncEvent event) { 
      } 

      public void onTimeout(AsyncEvent event) { 
       System.out.println("my asyncListener.onTimeout"); 
      } 
     }); 
     ServletInputStream input = request.getInputStream(); 
     ReadListener readListener = new ReadListenerImpl(input, response, context); 
     input.setReadListener(readListener); 
    } 

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

    } 
} 

RealListenerImpl:

public class ReadListenerImpl implements ReadListener{ 
    private ServletInputStream input = null; 
    private HttpServletResponse res = null; 
    private AsyncContext ac = null; 
    private Queue queue = new LinkedBlockingQueue(); 
    ReadListenerImpl(ServletInputStream in, HttpServletResponse r, AsyncContext c) { 
     input = in; 
     res = r; 
     ac = c; 
    } 
    public void onDataAvailable() throws IOException { 
     System.out.println("Data is available"); 

     StringBuilder sb = new StringBuilder(); 
     int len = -1; 
     byte b[] = new byte[1024]; 
     while (input.isReady() && (len = input.read(b)) != -1) { 
      String data = new String(b, 0, len); 
      sb.append(data); 
     } 
     queue.add(sb.toString()); 
    } 
    public void onAllDataRead() throws IOException { 
     System.out.println("Data is all read"); 

     // now all data are read, set up a WriteListener to write 
     ServletOutputStream output = res.getOutputStream(); 
     WriteListener writeListener = new WriteListenerImpl(output, queue, ac); 
     output.setWriteListener(writeListener); 
    } 
    public void onError(final Throwable t) { 
     ac.complete(); 
     t.printStackTrace(); 
    } 
} 

WriteListenerImpl:

public class WriteListenerImpl implements WriteListener{ 
    private ServletOutputStream output = null; 
    private Queue queue = null; 
    private AsyncContext context = null; 

    WriteListenerImpl(ServletOutputStream sos, Queue q, AsyncContext c) { 
     output = sos; 
     queue = q; 
     context = c; 
    } 

    public void onWritePossible() throws IOException { 
     while (queue.peek() != null && output.isReady()) { 
      String data = (String) queue.poll(); 
      output.print(data); 
     } 
     if (queue.peek() == null) { 
      context.complete(); 
     } 
    } 

    public void onError(final Throwable t) { 
     context.complete(); 
     t.printStackTrace(); 
    } 
} 

codes ci-dessus fonctionnent bien, je veux savoir quelles sont les différences avec le servlet IO de blocage? et je veux savoir comment fonctionne le code ci-dessus.

Répondre

0

données d'entrée de lecture:

Dans le scénario de blocage lorsque vous lisez des données à partir du flux d'entrée chaque lecture des blocs jusqu'à ce que les données sont disponibles. Cela peut être long pour un client distant qui envoie des données volumineuses, ce qui signifie que le thread est conservé pendant longtemps. Par exemple, considérez que les données entrantes sont reçues pendant 2 minutes à intervalles réguliers en 13 morceaux. En bloquant lisez vous lisez le premier morceau, maintenez le fil pendant ~ 10 secondes, lisez le morceau suivant, maintenez le fil pendant ~ 10 secondes etc. Dans ce cas, le fil pourrait passer moins d'une seconde en cours de traitement des données et près de 120 secondes bloquées en attente de données. Ensuite, si vous avez un serveur avec 10 threads, vous pouvez voir que vous auriez un débit de 10 clients toutes les 2 minutes. Dans le scénario non-bloquant, readListener lit les données tandis que isReady() renvoie true (il doit vérifier isReady() avant chaque appel pour lire les données), mais lorsque isReady() renvoie false, readListener renvoie et le thread est abandonné. . Puis, quand plus de données arrivent onDataAvailable() est appelée et readListener lit à nouveau les données jusqu'à ce que isReady soit false().

Dans le même exemple, cette fois le thread lit les données et renvoie, est réveillé 10 secondes plus tard, lit les données suivantes et renvoie, est réveillé 10 secondes plus tard, lit les données et renvoie etc. Cette fois, tandis qu'il a encore pris 2 minutes pour lire les données le (s) fil (s) nécessaire (s) pour le faire étaient seulement actifs pendant moins d'une seconde et étaient disponibles pour un autre travail. Ainsi, alors que la requête spécifique prend encore 2 minutes, le serveur avec 10 threads peut maintenant traiter beaucoup plus de requêtes toutes les 2 minutes.

Envoi des données de réponse:

Le scénario est similaire pour l'envoi de données et est utile lors de l'envoi de grandes réponses. Par exemple envoyer une grande réponse en 13 morceaux peut prendre 2 minutes pour envoyer le scénario de blocage parce que le client prend 10 secondes pour accuser réception de chaque morceau et le fil est tenu en attente. Cependant, dans le scénario non-bloquant, le thread n'est tenu que lors de l'envoi des données et non en attendant d'être en mesure d'envoyer à nouveau. Donc, encore une fois pour le client particulier, la réponse n'est pas envoyée plus rapidement mais le thread est maintenu pendant une fraction du temps et le débit du serveur qui traite la requête peut augmenter de manière significative.

Ainsi, les exemples ici sont artificiels mais utilisés pour illustrer un point. La clé étant que les E/S non bloquantes ne font pas une seule requête plus rapide qu'avec les E/S bloquantes, mais augmente le débit du serveur lorsque l'application peut lire les données d'entrée plus rapidement que le client peut envoyer et/ou envoyer les données de réponse plus rapidement que le client peut le recevoir.