2014-07-07 21 views
6

Sono abbastanza appassionato di Java NIO e voglio davvero applicare Java NIO al mio sistema attuale, ma quando ho creato questi esempi di applicazioni per confrontare tra Java IO e NIO, mi ha fatto molto deludere.Java IO vs NIO, qual è la differenza?

Qui ci sono i miei 2 campioni (non metto tutto il codice sorgente)

Java IO

public class BlockingServerClient { 

    private static final Logger log = Logger.getLogger(BlockingServerClient.class.getName()); 

    static final ExecutorService service = Executors.newCachedThreadPool(); 

    public static void main(String[] args) throws InterruptedException { 
     int port = Integer.parseInt(args[0]); 

     BlockingServerClient server = new BlockingServerClient(); 

     Server sr = server.new Server(port); 
     service.submit(sr); 
    } 

    private class Server implements Runnable { 

     ..... 

     public void run() { 
      ServerSocket ss = null; 
      try { 
       ss = new ServerSocket(localPort); 
       log.info("Server socket bound to " + localPort); 

       while (true) { 
        Socket client = ss.accept(); 
        log.info("Accepted connection from " + client.getRemoteSocketAddress()); 

        service.submit(new SocketClient(client)); 
       } 

      } catch (IOException e) { 
       log.log(Level.SEVERE, "Server error", e); 
      } finally { 
       ..... 
      } 
     } 
    } 

    private class SocketClient implements Runnable { 

     ..... 

     public void run() { 
      InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress(); 
      socketInfo = String.format("%s:%s", addr.getHostName(), addr.getPort()); 

      log.info("Start reading data from " + socketInfo); 
      try { 
       in = new BufferedReader(
         new InputStreamReader(socket.getInputStream())); 

       String input; 
       while ((input = in.readLine()) != null) { 
        log.info(String.format("[%s] %s", socketInfo, input)); 

        log.info("Socket " + socketInfo + " thread sleep 4s"); 
        TimeUnit.SECONDS.sleep(4); 
       } 

      } catch (Exception ex) { 
       log.log(Level.SEVERE, "Socket error", ex); 
      } finally { 
       ..... 
      } 
     } 
    } 
} 

Java NIO

public class NonBlockingServerClient { 

    private static final Logger log = Logger.getLogger(NonBlockingServerClient.class.getName()); 

    public static void main(String[] args) { 
     int port = Integer.parseInt(args[0]); 

     EventLoopGroup boss = new NioEventLoopGroup(); 
     EventLoopGroup worker = new NioEventLoopGroup(); 

     try { 
      NonBlockingServerClient sc = new NonBlockingServerClient(); 

      Server server = sc.new Server(port, boss, worker); 

      server.run(); 

     } catch (Exception e) { 
      log.log(Level.SEVERE, "Error", e); 
     } finally { 
      boss.shutdownGracefully(); 
      worker.shutdownGracefully(); 
     } 
    } 

    private class Server { 

     ..... 

     public void run() { 
      log.info("Start Server bootstrap"); 
      ServerBootstrap b = new ServerBootstrap(); 
      b.group(boss, worker) 
      .channel(NioServerSocketChannel.class) 
      .childHandler(new ChannelInitializer<Channel>() { 

       @Override 
       protected void initChannel(Channel ch) throws Exception { 
        ChannelPipeline pipe = ch.pipeline(); 
        pipe.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 
        pipe.addLast(new StringDecoder()); 
        pipe.addLast(new ClientHandler()); 
       } 
      }); 

      ChannelFuture future = null; 
      try { 
       future = b.bind(port).sync(); 
       future.channel().closeFuture().sync(); 
      } catch (InterruptedException e) { 
       log.log(Level.SEVERE, "Server binding error", e); 
       future.channel().close(); 
      } 

     } 
    } 

    private class ClientHandler extends SimpleChannelInboundHandler<String> { 

     @Override 
     protected void channelRead0(ChannelHandlerContext ctx, String msg) 
       throws Exception { 
      log.info(String.format("[%s] %s", ctx.channel().remoteAddress(), msg)); 
      log.info(ctx.channel().remoteAddress() + " sleep 4s"); 
      TimeUnit.SECONDS.sleep(4); 
     } 

    } 
} 

client

public class Client { 

    private static final Logger log = Logger.getLogger(Client.class.getName()); 

    public static void main(String[] args) throws InterruptedException { 
     int port = Integer.parseInt(args[0]); 

     for (int i = 0; i < 10; i++) { 
      Client cl = new Client("localhost", port); 
      cl.start(); 
      TimeUnit.MILLISECONDS.sleep(500); 
     } 
    } 

    String host; 
    int port; 

    public Client(String host, int port) { 
     this.host = host; 
     this.port =port; 
    } 

    public void start() { 
     log.info("Start client running"); 
     Socket socket = null; 
     String info = ""; 
     try { 
      socket = new Socket(host, port); 
      InetSocketAddress addr = (InetSocketAddress) socket.getLocalSocketAddress(); 
      info = String.format("%s:%s", addr.getHostName(), addr.getPort()); 
      int count = 10; 

      OutputStream out = socket.getOutputStream(); 
      while (count > 0) { 
       String outStr = "Output-" + count + "\n"; 
       out.write(outStr.getBytes()); 
       out.flush(); 
       count--; 
      } 
      out.write((info + "-Finish sending").getBytes()); 
      out.flush(); 
     } catch (Exception e) { 
      log.log(Level.SEVERE, "Client error", e); 
     } finally { 
      try { 
       socket.close(); 
       log.info(info + "-Client close"); 
      } catch (IOException e) { 
       log.log(Level.SEVERE, "Closing client error", e); 
      } 
     } 
    } 
} 

Il client durante l'esecuzione verrà creato e 10 client si connettono al server. Dopo essere stato eseguito e monitorato più volte, non ho trovato differenze tra Java IO e NIO.

Se il numero di clienti cambiato a 500, ho trovato che il java IO veramente creato 500 discussioni, ma il consumo di dati veramente veloce. Al contrario, l'applicazione NIO Java aveva un numero di thread molto inferiore rispetto all'altro, ma il consumo di dati era lento e ci voleva più tempo per completare tutto.

Quindi, qual è il vantaggio di Java NIO? Crea meno thread per risparmiare memoria, ma rallentando le prestazioni.

Oppure, potrei farlo in modo errato.

risposta

6

La differenza di velocità che si nota è dovuta al sonno di 4 secondi che appare in entrambi i casi di test.

Nel caso non NIO, che ha un thread per ogni richiesta, letto per 4 secondi solo i blocchi che una richiesta. Tuttavia nel caso NIO, che ha un numero molto minore di thread worker, blocca quella richiesta e ogni altra richiesta che è in attesa di essere eseguita su quel thread.

Quindi questo pone la questione, perché vorremmo usare meno le discussioni con l'approccio NIO? E la risposta è la scalabilità. I moderni sistemi operativi presentano un problema di ridimensionamento legato al numero di thread bloccati sull'IO di rete. Vedi il problema C10K per maggiori dettagli.

In generale mi trovo NIO per essere più veloce, o almeno ha il potenziale per essere molto più veloce se:

  1. Lo si utilizza per evitare i buffer di copia in tutto
  2. E di evitare tutto ciò che può bloccare i fili. ad esempio, non bloccare su un database fetch ecc

Questo è dove quadri asincrone come akka brillantezza.

+0

Come menzionato [qui] (https://stackoverflow.com/q/46965752/3317808), NIO- non bloccante IO, è un singolo modello di programmazione filettato che coinvolge selezionare() '' chiamata di sistema internamente. Non sono sicuro, perché confrontiamo l'I/O bloccato con thread con NIO con thread. – overexchange

Problemi correlati