2012-02-05 27 views
6

Son zamanlarda, daha yeni bilgisayarlarda Java'nın I/O'larının çok çekirdekli makinelerin yeni kullanılabilirliği nedeniyle NIO'dan daha iyi performans gösterdiğini okudum.Java I/O vs NIO: Hızlı Karşılaştırma Karşılaştırması

Yerel bağlantı döngü adresi kullanılarak LAN üzerinden I/O ve NIO aktarma sürelerini karşılaştırarak hızlı bir test yaptım.

Not:

I/O transferler 21789.3ms

NIO transferler 22771.0ms

ortalaması ortalama Bu JDK'yi 7

sonuçları (3 deneme) kullanılarak bir Ayrıca, CPU kullanımının her bir NIO aktarımında I/O ile karşılaştırıldığında yaklaşık% 10 daha yüksek olduğu görülmüştür.

Karşılaştırma kodum adil mi? İyi/eşit I/O ve NIO kodu yazdım mı? Değilse, bu testi nasıl geliştirebilirim ve yeniden çalıştırabilirim?

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(); 
     } 
    } 
} 

Ek Bilgi: Dell Studio

Windows Vista (SP2) XPS 435MT'yi

1 gen i7 dört çekirdekli işlemci 2.67GHz

6GB RAM

64 bit mimari

+1

ben bu kıyaslama bölümü adil olduğuna ikna değilim - Java, gerçekten JVM ve tüm ısınmak gibi şeyler yapmak gerekiyor. Http://code.google.com/p/caliper/ gibi bir karşılaştırma aracı kullanabilirsiniz. –

+0

@LouisWasserman JVM'yi ısıtmayı ve/veya bu kodu iyileştirmeyi nasıl öneriyorsunuz? – bgroenks

+1

Esasen JVM'yi ne yaptığını bilen kişiler tarafından oluşturulan bir kıyaslama çerçevesi kullanın. Kendi "zamanlama işlemi" kodunu yazmayın. Yanlış anlaman için daha çok yol var. –

cevap

3

Öneriler

  • Bloke IO'yu NIO'yu bloke ederek karşılaştırmayı deneyin. Kodunuz daha kısa olacak. IO'yu test edecekseniz, istemcide ve sunucuda IO kullanın. NIO kullanacaksanız, her iki ucunda da aynısını kullanın.
  • Doğrudan ByteBuffers kullanın.
  • Dosyaları karşılaştırmanın bir parçası olmadıklarından okuma/yazma ve çok daha yavaş olabilir. Sadece boş veri bloklarını geç.
  • Farklı blok boyutlarını deneyin, örn. 8 KB.
  • Değiştirmek istediğiniz veri türünü düşünün. Örneğin. ByteBuffer, int ve long daha verimli okuma yapabilir.
  • Numaraları bant genişliği açısından rapor edin. Döngüde 1-3 GB/sn arasında bir süre görmeyi beklerdim.

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

+0

İpuçları için teşekkürler. – bgroenks

+0

Bağlantıyı ilginç bulabilirsiniz. –

+0

Threading modeliyle ne demek istiyor? – bgroenks

İlgili konular