2012-02-05 4 views
6

Recientemente leí que en las computadoras más nuevas la E/S de Java funciona mejor que NIO debido a la nueva disponibilidad de las máquinas de varios núcleos.Java I/O vs NIO: Comparación rápida de puntos de referencia

Realicé una prueba rápida comparando el tiempo de transferencia de E/S y NIO en la LAN utilizando la dirección de bucle localhost.

Nota: Este es el uso de JDK 7

Los resultados (3 ensayos):

I/O transferencias promediaron 21789.3ms

transferencias NIO promediaron 22771.0ms

También vale la pena señalar que el uso de la CPU parece ser un 10% mayor en cada transferencia de NIO en comparación con la E/S.

Mi pregunta es si mi código de comparación es justo. ¿Escribí E/S buena/igual y el código NIO? Si no, ¿cómo puedo mejorar y volver a ejecutar esta prueba?

public static void main(String[] args) { 
    System.out.println("Initiating test sequence..."); 
    new Thread(new Client()).start(); 
    try { 
     System.out.println("Server I/O initiating..."); 
     ServerSocket server = new ServerSocket(5555); 
     Socket sock = server.accept(); 
     System.out.println("Server connected to client successfully"); 
     InputStream is = sock.getInputStream(); 
     File output = new File("C:/test_root/video.avi"); 
     FileOutputStream fos = new FileOutputStream(output); 
     byte[] data = new byte[1024]; 
     int len=0; 
     System.out.println("Server initiating transfer - Timer starting"); 
     long start = System.currentTimeMillis(); 
     while((len=is.read(data))>0) { 
      fos.write(data, 0, len); 
      fos.flush(); 
     } 
     fos.close(); 
     is.close(); 
     sock.close(); 
     server.close(); 
     long end = System.currentTimeMillis(); 
     System.out.println("Network I/O transfer time = "+(end-start)+"ms"); 

     System.out.println("Server NIO initiating..."); 
     ServerSocketChannel serverChan = ServerSocketChannel.open(); 
     serverChan.bind(new InetSocketAddress(5555)); 
     SocketChannel chan = serverChan.accept(); 
     chan.configureBlocking(false); 
     System.out.println("Server channel connected"); 
     FileChannel fc = (FileChannel) Files.newByteChannel(Paths.get("C:/test_root/video.avi"), StandardOpenOption.CREATE, StandardOpenOption.WRITE); 
     ByteBuffer buff = ByteBuffer.allocate(1024); 
     System.out.println("Server initiating transfer - Timer starting"); 
     start = System.currentTimeMillis(); 
     while(chan.read(buff)>=0 || buff.position() > 0) { 
      buff.flip(); 
      fc.write(buff); 
      buff.compact(); 
     } 
     chan.close(); 
     fc.close(); 
     serverChan.close(); 
     end = System.currentTimeMillis(); 
     System.out.println("Network NIO transfer time = "+(end-start)+"ms"); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    System.out.println("Test completed!"); 
} 

static class Client implements Runnable { 

    public void run() { 
     try { 
      System.out.println("Client I/O initiating..."); 
      Socket sock = new Socket("localhost", 5555); 
      System.out.println("Client connected to server successfully!"); 
      OutputStream os = sock.getOutputStream(); 
      File input = new File(System.getProperty("user.home")+"/Documents/clip0025.avi"); 
      FileInputStream fis = new FileInputStream(input); 
      byte[] data = new byte[1024]; 
      int len=0; 
      int tot=0; 
      int perc=0; 
      while((len=fis.read(data))>0) { 
       os.write(data, 0, len); 
       os.flush(); 
       tot+=len; 
       int prev = perc; 
       perc = getPercentage(tot, input.length()); 
       if(perc !=prev && (perc == 10 || perc == 25 || perc == 50 || perc == 75 || perc == 98)) 
        System.out.println("Client reporting: "+perc+"% read"); 
      } 
      os.close(); 
      fis.close(); 
      sock.close(); 

      try { 
       Thread.sleep(2000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      System.out.println("Client NIO initiating..."); 
      SocketChannel sc = SocketChannel.open(); 
      boolean connected = sc.connect(new InetSocketAddress("localhost",5555)); 
      if(!connected) 
       connected = sc.finishConnect(); 
      if(!connected) 
       throw(new IOException("Client failed to connect")); 
      System.out.println("Client channel connected"); 
      sc.configureBlocking(false); 
      FileChannel fc = (FileChannel) Files.newByteChannel(input.toPath(), StandardOpenOption.READ); 
      ByteBuffer buff = ByteBuffer.allocate(1024); 
      len=0; 
      tot=0; 
      while((len=fc.read(buff))>=0||buff.position()>0) { 
       buff.flip(); 
       sc.write(buff); 
       buff.compact(); 
       tot+=len; 
       int prev = perc; 
       perc = getPercentage(tot, input.length()); 
       if(perc !=prev && (perc == 10 || perc == 25 || perc == 50 || perc == 75 || perc == 98)) 
        System.out.println("Client reporting: "+perc+"% read"); 
      } 
      sc.close(); 
      fc.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Información adicional:

Windows Vista (SP2) en Dell Studio XPS 435mt

primera procesador de cuatro núcleos generación i7 2.67GHz

6 GB de RAM

de 64 bits arquitectura

+1

no estoy convencido de que la parte de la evaluación comparativa de esto es justo - en Java, que realmente tiene que hacer cosas como calentar el JVM y todo. Es posible que pueda utilizar una herramienta de evaluación comparativa como http://code.google.com/p/caliper/. –

+0

@LouisWasserman ¿Cómo sugeriría calentar la JVM y/o mejorar este código? – bgroenks

+1

Utilice un marco de evaluación comparativa creado por personas que saben lo que están haciendo con la JVM, en esencia. No escriba su propio código "cronometrando una operación". Hay muchas más maneras de equivocarse que de hacerlo bien. –

Respuesta

3

Sugerencias

  • Intente comparar el bloqueo de E/S con el bloqueo de NIO. Tu código será más corto. Si va a probar IO, use IO en el cliente y el servidor. Si va a utilizar NIO, use el mismo en ambos extremos.
  • Utilice ByteBuffers directo.
  • No lea/escriba en los archivos, ya que no son parte del índice de referencia y pueden ser mucho más lentos. Simplemente pase alrededor de bloques de datos en blanco.
  • Pruebe diferentes tamaños de bloques, p. 8 KB.
  • Tenga en cuenta el tipo de datos que desea intercambiar. p.ej. ByteBuffer puede hacer que leer int y long sea más eficiente.
  • Indique los números en términos de ancho de banda. Esperaría ver entre 1 y 3 GB/seg. Por vuelta.

http://vanillajava.blogspot.com/2010/07/java-nio-is-faster-than-java-io-for.html

+0

Gracias por los consejos. – bgroenks

+0

Puede encontrar el enlace interesante. –

+0

¿Qué quiere decir con el modelo de subprocesamiento? – bgroenks

Cuestiones relacionadas