2009-06-08 11 views
15

내 하드 디스크에 두 (2GB 각각) 파일을 가지고 서로를 비교할 :자바 대용량 파일 디스크 IO 성능

  • 을 원본 파일을 복사 윈도우 탐색기가 약합니다 함께. 2-4 분 (읽기 및 쓰기 - 동일한 실제 및 논리 디스크에 있음).
  • java.io.FileInputStream을 두 번 읽고 바이트 단위로 바이트 배열을 비교하는 데 20 분 이상 걸립니다.
  • 버퍼가 64kb이면 파일을 청크로 읽고 비교합니다. 수행
  • 비교

    int numRead = Math.min(numRead[0], numRead[1]); 
    for (int k = 0; k < numRead; k++) 
    { 
        if (buffer[1][k] != buffer[0][k]) 
        { 
         return buffer[0][k] - buffer[1][k]; 
        } 
    } 
    

내가 무엇을 할 수와 같은 꽉 루프가이 속도를하는 것입니다? NIO가 평범한 시내보다 빠르다고 생각합니까? Java가 DMA/SATA 기술을 사용할 수없고 느린 OS-API 호출을 대신합니까?

편집 :
답변 해 주셔서 감사합니다. 나는 그들을 바탕으로 몇 가지 실험을했습니다. 안드레아스가 보여준대로

스트림 또는 nio 접근 방식은 크게 다르지 않습니다.
올바른 버퍼 크기가 더 중요합니다.

이것은 내 자신의 실험으로 확인되었습니다. 파일을 큰 덩어리로 읽으므로 추가 버퍼 (BufferedInputStream)도 아무 것도주지 않습니다. 비교 최적화가 가능하고 32 배 풀기로 최상의 결과를 얻었지만 디스크 읽기에 비해 비교 시간이 적으므로 속도가 빨라집니다. 내가 할 수있는 일은 ;-(같은 큰 파일을

+1

참고 : 기본적으로 DMA/SATA 기술은 모든 파일 I/O 작업 (현재 OS에서는 잘)을 위해 OS에서 처리합니다. –

답변

13

8KB와 1MB 사이의 버퍼 크기를 가진 두 개의 동일한 3,8gb 파일을 비교하는 세 가지 방법을 시도했습니다. 첫 번째 첫 번째 방법은 두 개의 버퍼링 된 입력 스트림을 사용했습니다.

두 번째 방법은 두 개의 다른 스레드를 읽고 세 번째 방법으로 비교하는 스레드 풀을 사용합니다. 이것은 높은 CPU 사용량을 희생하여 약간 높은 처리량을 얻었습니다. 스레드 풀 관리는 짧은 실행 작업으로 많은 오버 헤드를 필요로합니다.

세 번째 방법은 당신이 볼 수 있듯이, 일반적인 접근 방식은 크게 다르지 않다 laginimaineb

에 의해 게시 된, NIO 사용합니다. 올바른 버퍼 크기가 더 중요합니다.

스레드를 사용하여 1 바이트 이하를 읽는 것이 이상합니다. 힘든 오류를 발견하지 못했습니다. 사용

comparing just with two streams 
I was equal, even after 3684070360 bytes and reading for 704813 ms (4,98MB/sec * 2) with a buffer size of 8 kB 
I was equal, even after 3684070360 bytes and reading for 578563 ms (6,07MB/sec * 2) with a buffer size of 16 kB 
I was equal, even after 3684070360 bytes and reading for 515422 ms (6,82MB/sec * 2) with a buffer size of 32 kB 
I was equal, even after 3684070360 bytes and reading for 534532 ms (6,57MB/sec * 2) with a buffer size of 64 kB 
I was equal, even after 3684070360 bytes and reading for 422953 ms (8,31MB/sec * 2) with a buffer size of 128 kB 
I was equal, even after 3684070360 bytes and reading for 793359 ms (4,43MB/sec * 2) with a buffer size of 256 kB 
I was equal, even after 3684070360 bytes and reading for 746344 ms (4,71MB/sec * 2) with a buffer size of 512 kB 
I was equal, even after 3684070360 bytes and reading for 669969 ms (5,24MB/sec * 2) with a buffer size of 1024 kB 
comparing with threads 
I was equal, even after 3684070359 bytes and reading for 602391 ms (5,83MB/sec * 2) with a buffer size of 8 kB 
I was equal, even after 3684070359 bytes and reading for 523156 ms (6,72MB/sec * 2) with a buffer size of 16 kB 
I was equal, even after 3684070359 bytes and reading for 527547 ms (6,66MB/sec * 2) with a buffer size of 32 kB 
I was equal, even after 3684070359 bytes and reading for 276750 ms (12,69MB/sec * 2) with a buffer size of 64 kB 
I was equal, even after 3684070359 bytes and reading for 493172 ms (7,12MB/sec * 2) with a buffer size of 128 kB 
I was equal, even after 3684070359 bytes and reading for 696781 ms (5,04MB/sec * 2) with a buffer size of 256 kB 
I was equal, even after 3684070359 bytes and reading for 727953 ms (4,83MB/sec * 2) with a buffer size of 512 kB 
I was equal, even after 3684070359 bytes and reading for 741000 ms (4,74MB/sec * 2) with a buffer size of 1024 kB 
comparing with nio 
I was equal, even after 3684070360 bytes and reading for 661313 ms (5,31MB/sec * 2) with a buffer size of 8 kB 
I was equal, even after 3684070360 bytes and reading for 656156 ms (5,35MB/sec * 2) with a buffer size of 16 kB 
I was equal, even after 3684070360 bytes and reading for 491781 ms (7,14MB/sec * 2) with a buffer size of 32 kB 
I was equal, even after 3684070360 bytes and reading for 317360 ms (11,07MB/sec * 2) with a buffer size of 64 kB 
I was equal, even after 3684070360 bytes and reading for 643078 ms (5,46MB/sec * 2) with a buffer size of 128 kB 
I was equal, even after 3684070360 bytes and reading for 865016 ms (4,06MB/sec * 2) with a buffer size of 256 kB 
I was equal, even after 3684070360 bytes and reading for 716796 ms (4,90MB/sec * 2) with a buffer size of 512 kB 
I was equal, even after 3684070360 bytes and reading for 652016 ms (5,39MB/sec * 2) with a buffer size of 1024 kB 

코드 :

import junit.framework.Assert; 
import org.junit.Before; 
import org.junit.Test; 

import java.io.BufferedInputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.nio.ByteBuffer; 
import java.nio.channels.FileChannel; 
import java.text.DecimalFormat; 
import java.text.NumberFormat; 
import java.util.Arrays; 
import java.util.concurrent.*; 

public class FileCompare { 

    private static final int MIN_BUFFER_SIZE = 1024 * 8; 
    private static final int MAX_BUFFER_SIZE = 1024 * 1024; 
    private String fileName1; 
    private String fileName2; 
    private long start; 
    private long totalbytes; 

    @Before 
    public void createInputStream() { 
     fileName1 = "bigFile.1"; 
     fileName2 = "bigFile.2"; 
    } 

    @Test 
    public void compareTwoFiles() throws IOException { 
     System.out.println("comparing just with two streams"); 
     int currentBufferSize = MIN_BUFFER_SIZE; 
     while (currentBufferSize <= MAX_BUFFER_SIZE) { 
      compareWithBufferSize(currentBufferSize); 
      currentBufferSize *= 2; 
     } 
    } 

    @Test 
    public void compareTwoFilesFutures() 
      throws IOException, ExecutionException, InterruptedException { 
     System.out.println("comparing with threads"); 
     int myBufferSize = MIN_BUFFER_SIZE; 
     while (myBufferSize <= MAX_BUFFER_SIZE) { 
      start = System.currentTimeMillis(); 
      totalbytes = 0; 
      compareWithBufferSizeFutures(myBufferSize); 
      myBufferSize *= 2; 
     } 
    } 

    @Test 
    public void compareTwoFilesNio() throws IOException { 
     System.out.println("comparing with nio"); 
     int myBufferSize = MIN_BUFFER_SIZE; 
     while (myBufferSize <= MAX_BUFFER_SIZE) { 
      start = System.currentTimeMillis(); 
      totalbytes = 0; 
      boolean wasEqual = isEqualsNio(myBufferSize); 

      if (wasEqual) { 
       printAfterEquals(myBufferSize); 
      } else { 
       Assert.fail("files were not equal"); 
      } 

      myBufferSize *= 2; 
     } 

    } 

    private void compareWithBufferSize(int myBufferSize) throws IOException { 
     final BufferedInputStream inputStream1 = 
       new BufferedInputStream(
         new FileInputStream(new File(fileName1)), 
         myBufferSize); 
     byte[] buff1 = new byte[myBufferSize]; 
     final BufferedInputStream inputStream2 = 
       new BufferedInputStream(
         new FileInputStream(new File(fileName2)), 
         myBufferSize); 
     byte[] buff2 = new byte[myBufferSize]; 
     int read1; 

     start = System.currentTimeMillis(); 
     totalbytes = 0; 
     while ((read1 = inputStream1.read(buff1)) != -1) { 
      totalbytes += read1; 
      int read2 = inputStream2.read(buff2); 
      if (read1 != read2) { 
       break; 
      } 
      if (!Arrays.equals(buff1, buff2)) { 
       break; 
      } 
     } 
     if (read1 == -1) { 
      printAfterEquals(myBufferSize); 
     } else { 
      Assert.fail("files were not equal"); 
     } 
     inputStream1.close(); 
     inputStream2.close(); 
    } 

    private void compareWithBufferSizeFutures(int myBufferSize) 
      throws ExecutionException, InterruptedException, IOException { 
     final BufferedInputStream inputStream1 = 
       new BufferedInputStream(
         new FileInputStream(
           new File(fileName1)), 
         myBufferSize); 
     final BufferedInputStream inputStream2 = 
       new BufferedInputStream(
         new FileInputStream(
           new File(fileName2)), 
         myBufferSize); 

     final boolean wasEqual = isEqualsParallel(myBufferSize, inputStream1, inputStream2); 

     if (wasEqual) { 
      printAfterEquals(myBufferSize); 
     } else { 
      Assert.fail("files were not equal"); 
     } 
     inputStream1.close(); 
     inputStream2.close(); 
    } 

    private boolean isEqualsParallel(int myBufferSize 
      , final BufferedInputStream inputStream1 
      , final BufferedInputStream inputStream2) 
      throws InterruptedException, ExecutionException { 
     final byte[] buff1Even = new byte[myBufferSize]; 
     final byte[] buff1Odd = new byte[myBufferSize]; 
     final byte[] buff2Even = new byte[myBufferSize]; 
     final byte[] buff2Odd = new byte[myBufferSize]; 
     final Callable<Integer> read1Even = new Callable<Integer>() { 
      public Integer call() throws Exception { 
       return inputStream1.read(buff1Even); 
      } 
     }; 
     final Callable<Integer> read2Even = new Callable<Integer>() { 
      public Integer call() throws Exception { 
       return inputStream2.read(buff2Even); 
      } 
     }; 
     final Callable<Integer> read1Odd = new Callable<Integer>() { 
      public Integer call() throws Exception { 
       return inputStream1.read(buff1Odd); 
      } 
     }; 
     final Callable<Integer> read2Odd = new Callable<Integer>() { 
      public Integer call() throws Exception { 
       return inputStream2.read(buff2Odd); 
      } 
     }; 
     final Callable<Boolean> oddEqualsArray = new Callable<Boolean>() { 
      public Boolean call() throws Exception { 
       return Arrays.equals(buff1Odd, buff2Odd); 
      } 
     }; 
     final Callable<Boolean> evenEqualsArray = new Callable<Boolean>() { 
      public Boolean call() throws Exception { 
       return Arrays.equals(buff1Even, buff2Even); 
      } 
     }; 

     ExecutorService executor = Executors.newCachedThreadPool(); 
     boolean isEven = true; 
     Future<Integer> read1 = null; 
     Future<Integer> read2 = null; 
     Future<Boolean> isEqual = null; 
     int lastSize = 0; 
     while (true) { 
      if (isEqual != null) { 
       if (!isEqual.get()) { 
        return false; 
       } else if (lastSize == -1) { 
        return true; 
       } 
      } 
      if (read1 != null) { 
       lastSize = read1.get(); 
       totalbytes += lastSize; 
       final int size2 = read2.get(); 
       if (lastSize != size2) { 
        return false; 
       } 
      } 
      isEven = !isEven; 
      if (isEven) { 
       if (read1 != null) { 
        isEqual = executor.submit(oddEqualsArray); 
       } 
       read1 = executor.submit(read1Even); 
       read2 = executor.submit(read2Even); 
      } else { 
       if (read1 != null) { 
        isEqual = executor.submit(evenEqualsArray); 
       } 
       read1 = executor.submit(read1Odd); 
       read2 = executor.submit(read2Odd); 
      } 
     } 
    } 

    private boolean isEqualsNio(int myBufferSize) throws IOException { 
     FileChannel first = null, seconde = null; 
     try { 
      first = new FileInputStream(fileName1).getChannel(); 
      seconde = new FileInputStream(fileName2).getChannel(); 
      if (first.size() != seconde.size()) { 
       return false; 
      } 
      ByteBuffer firstBuffer = ByteBuffer.allocateDirect(myBufferSize); 
      ByteBuffer secondBuffer = ByteBuffer.allocateDirect(myBufferSize); 
      int firstRead, secondRead; 
      while (first.position() < first.size()) { 
       firstRead = first.read(firstBuffer); 
       totalbytes += firstRead; 
       secondRead = seconde.read(secondBuffer); 
       if (firstRead != secondRead) { 
        return false; 
       } 
       if (!nioBuffersEqual(firstBuffer, secondBuffer, firstRead)) { 
        return false; 
       } 
      } 
      return true; 
     } finally { 
      if (first != null) { 
       first.close(); 
      } 
      if (seconde != null) { 
       seconde.close(); 
      } 
     } 
    } 

    private static boolean nioBuffersEqual(ByteBuffer first, ByteBuffer second, final int length) { 
     if (first.limit() != second.limit() || length > first.limit()) { 
      return false; 
     } 
     first.rewind(); 
     second.rewind(); 
     for (int i = 0; i < length; i++) { 
      if (first.get() != second.get()) { 
       return false; 
      } 
     } 
     return true; 
    } 

    private void printAfterEquals(int myBufferSize) { 
     NumberFormat nf = new DecimalFormat("#.00"); 
     final long dur = System.currentTimeMillis() - start; 
     double seconds = dur/1000d; 
     double megabytes = totalbytes/1024/1024; 
     double rate = (megabytes)/seconds; 
     System.out.println("I was equal, even after " + totalbytes 
       + " bytes and reading for " + dur 
       + " ms (" + nf.format(rate) + "MB/sec * 2)" + 
       " with a buffer size of " + myBufferSize/1024 + " kB"); 
    } 
} 
+0

+1. 좋은 일, Andreas. 같은 데이터와 머신에서 64MB (네, 메가 바이트)의 버퍼로 실행할 수 있습니까? @alamar는 이것이 당신의 자신의 결과에 더 가깝게 실제 경험을하는 것에 회의적 인 추구의 부족 때문에 이것이 어떻게해서든지 마술처럼 훌륭한 결과를 전달할 것이라고 생각합니다. –

+1

나의 실험에서도 테스트와 마찬가지로 버퍼 크기가 64kb/128kb가 최적이라는 것을 보여주었습니다. 한 단계에서 64KB의 byte []를 읽으려면 FileInputStream 위에 BufferedInputStream을 사용할지 여부는 중요하지 않습니다. 파일을 한 번 읽은 후에 타이밍이 디스크 캐싱으로 인해 작아지기 때문에 문제가 발생했습니다. –

7

, 당신은 또한, 자바 스트림을 단일 바이트를 읽는 것은 매우 느릴 수 있습니다 java.nio.

훨씬 더 나은 성능을 얻을거야 이없는 것 같습니다. 사용 바이트 배열 (내 경험에 따른 2-6K 요소, ymmv는 플랫폼/응용 프로그램과 유사하므로) 스트림을 사용하면 읽기 성능이 크게 향상됩니다.

+0

나는 그것을 두려워했다. 코드는 꽤 오래되었고 오래 동안 잘 작동했지만 파일은 항상 커지는 경향이 있습니다. –

+1

MappedByteBuffer (OS의 가상 메모리 페이징 서브 시스템을 사용함)를 사용하면 코드 변경을 최소화 할 수있을 것입니다. 속도가 크게 향상됩니다. 나는 "규모의 순서"를 더 빨리 추측 할 것이다. –

+1

NIO는 혼란 스러울 수 있으므로 ByteBuffer.allocateDirect()로 시작하여 최고 성능을 얻고 싶습니다 (이 시점에서 메모리 매핑 파일을 사용함). http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html – AgileJon

6

Java를 사용하여 파일을 읽고 쓰는 것도 매우 빠릅니다. FileChannels을 사용하십시오. 파일을 비교할 때, 분명히 이것은 많은 시간이 걸릴 것입니다. c 를 바이트 omparing 바이트는 다음 (더 최적화 될 수있다) FileChannels 및 ByteBuffer의 사용 예이다 :

public static boolean compare(String firstPath, String secondPath, final int BUFFER_SIZE) throws IOException { 
    FileChannel firstIn = null, secondIn = null; 
    try { 
     firstIn = new FileInputStream(firstPath).getChannel(); 
     secondIn = new FileInputStream(secondPath).getChannel(); 
     if (firstIn.size() != secondIn.size()) 
      return false; 
     ByteBuffer firstBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE); 
     ByteBuffer secondBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE); 
     int firstRead, secondRead; 
     while (firstIn.position() < firstIn.size()) { 
      firstRead = firstIn.read(firstBuffer); 
      secondRead = secondIn.read(secondBuffer); 
      if (firstRead != secondRead) 
       return false; 
      if (!buffersEqual(firstBuffer, secondBuffer, firstRead)) 
       return false; 
     } 
     return true; 
    } finally { 
     if (firstIn != null) firstIn.close(); 
     if (secondIn != null) firstIn.close(); 
    } 
} 

private static boolean buffersEqual(ByteBuffer first, ByteBuffer second, final int length) { 
    if (first.limit() != second.limit()) 
     return false; 
    if (length > first.limit()) 
     return false; 
    first.rewind(); second.rewind(); 
    for (int i=0; i<length; i++) 
     if (first.get() != second.get()) 
      return false; 
    return true; 
} 
+0

바이트 당 바이트보다 빠른 비교에 대한 아이디어가 있습니까? –

+0

음 ... 내가 말했듯이 FileChannels (및 ByteBuffers)를 사용할 수 있습니다. 두 개의 1.6GB 파일을 60 초 동안 비교할 수 있습니다. 내가 사용한 코드를 포함하도록 원래 게시물을 편집했습니다. – laginimaineb

+0

이 예제가 마음에 들어요. 그들을 비교하기 위해 배열로 WHOLE 파일을 읽을 필요가 없습니다. 그렇지 않으면 2 바이트를 읽는 대신 바이트 1에서 동일한 파일을 읽는 데 많은 시간을 낭비하게됩니다. –

0

DMA/SATA 하드웨어/로우 레벨 techlonogies이며 어떠한 프로그래밍 언어로 보이지 않는다.

메모리 매핑 된 입력/출력의 경우 java.nio를 사용해야합니다.

1 바이트로 파일을 읽지 않습니까? 그게 낭비 일 것이고, 블록 단위로하는 것이 좋을 것이고 각 블록은 탐색을 최소화하기 위해 64 메가 바이트와 같아야합니다.

+0

당신은 64kb를 의미합니까? 메가 바이트가 아닌가요? –

+0

당신이 그것을 감당할 수 있다면 왜, 메가 바이트 (당신은 오늘 할 수 있습니다). 두 파일을 64 킬로바이트로 읽는 것은 IMO가 좋은 아이디어가 아닙니다. 드라이브가 끝없이 탐색 할 것이기 때문입니다. – alamar

+0

오, 그것이 유형이라고 생각했습니다. 조기 최적화와 같은 냄새가 난다. 나는 64MB 전체가 읽혀질 때까지 읽기가 차단되어 전반적인 성능이 느려지므로 이러한 큰 값에 의문을 제기합니다. 결론적으로 실제 성능 메트릭 만 표시되지만, 나는 당신의 이론에 회의적입니다. –

2

Suns Article for I/O Tuning (이미 약간 날짜가 있음)을 살펴볼 수 있습니다. 거기에있는 예제와 코드 사이에 유사점을 찾을 수 있습니다.또한 java.io보다 더 빠른 I/O 요소를 포함하는 java.nio 패키지를 살펴보십시오. Dr. Dobbs Journal은 high performance IO using java.nio에 관한 아주 좋은 기사를 가지고 있습니다.

그렇다면 코드 속도를 높이는 데 도움이 될 수있는 추가 예제와 튜닝 팁이 있습니다.

또한 Arrays 클래스는 methods for comparing byte arrays 빌드를 가지고 있습니다. 어쩌면 이것들을 사용하여 작업을 더 빠르게하고 루프를 약간 정리할 수도 있습니다.

+0

Arrays 클래스를 사용하는 것이 좋습니다. 후드 아래에서는 밀접한 루프에서 바이트 단위 비교를 수행합니다. 현재 사용중인 32 배의 언 롤링 루프만큼 빠르지는 않지만 코드를 상당히 단축합니다 (특히 esp. IO 성능 테스트 용. –

5

다음은 java에서 파일을 읽는 다양한 방법의 상대적 장점에 대한 좋은 기사입니다. 일부 유용 할 수 있습니다 :

How to read files quickly

+0

링크에 대한 감사의 말 !!!!!!!!!! – Ahamed

1

을 더 나은 비교를 위해 한 번에 두 개의 파일을 복사하려고합니다. 하드 드라이브는 두 개를 읽는 것보다 훨씬 효율적으로 하나의 파일을 읽을 수 있습니다 (머리가 앞뒤로 움직여 읽어야하므로) 이 방법을 줄이는 한 가지 방법은 더 큰 버퍼를 사용하는 것입니다. 16 MB. ByteBuffer를 사용합니다.

ByteBuffer를 사용하면 getLong()

자바 효율적인 경우 긴 값을 비교하여 한 번에 8 바이트를 비교할 수 있습니다, 대부분의 작업은 읽기 위해 디스크/OS에 있으며 그렇게 shouldn 작성 다른 언어를 사용하는 것보다 훨씬 느립니다 (디스크/OS가 병목 현상이 있음)

코드에서 버그가 아닌 것으로 판단 할 때까지는 Java가 느리다고 생각하지 마십시오.

+0

비행 중에 지어 질 필요가 있기 때문에 나는 longs를 비교하는 것에 질문한다. 루프를 8 번 실행하는 것이 더 빠르지 않아야합니까? (또는 내 실험에서 최적 인 것처럼 보이는 32 회). 나는 "선택이 깨지지 않는다"는 것에 동의한다. IO는 빠르지 만, Java IO가/Pascal/C IO보다 훨씬 느리다는 것을 과거로부터 알고있다. 하지만 대부분의 애플 리케이션이 일반 IO 이상을 포함하고 있기 때문에 Java는 현재 전체적으로 더 빠릅니다. –

+0

직접적인 ByteBuffers의 경우, long은 Java로 구성되지 않습니다. 그것은 JNI에 대한 하나의 호출입니다 (C 코드로 생성 될 수도 있습니다). 저는 바이트 당 하나의 호출보다 빠릅니다. 나중의 대답에서 나는 이것이 @ 74를 수행한다는 것을 증명한다.동일한 디스크에서 8MB/s의 속도로 읽기가 가능한 두 개의 파일 읽기. –

+0

@ Peter Lawrey : 큰 버퍼를 테스트 했습니까? OS가 여러 개의 파일을 프리 페치 (prefetch) 할 수 있고 그것을 수행 할 때 내부적으로 거대한 버퍼를 사용하는 것처럼 보인 것은 당신이 말하는 것입니다. (http://stackoverflow.com/a/11610367/581205) – maaartinus

6

당신 NIO 나는 다음과 같은 결과를 얻을 기능을 비교 수정 후.

I was equal, even after 4294967296 bytes and reading for 304594 ms (13.45MB/sec * 2) with a buffer size of 1024 kB 
I was equal, even after 4294967296 bytes and reading for 225078 ms (18.20MB/sec * 2) with a buffer size of 4096 kB 
I was equal, even after 4294967296 bytes and reading for 221351 ms (18.50MB/sec * 2) with a buffer size of 16384 kB 

참고 :이 파일은 의미 :이/s의 빠른

I was equal, even after 4294967296 bytes and reading for 178087 ms (23.00MB/sec * 2) with a buffer size of 1024 kB 
I was equal, even after 4294967296 bytes and reading for 119084 ms (34.40MB/sec * 2) with a buffer size of 4096 kB 
I was equal, even after 4294967296 bytes and reading for 109549 ms (37.39MB/sec * 2) with a buffer size of 16384 kB 

주 드라이브에 같은 일을 실행

가 파일을 37 메가 바이트 속도로 읽는 의미 74의 비율로 읽힌다.8MB/s

private static boolean nioBuffersEqual(ByteBuffer first, ByteBuffer second, final int length) { 
    if (first.limit() != second.limit() || length > first.limit()) { 
     return false; 
    } 
    first.rewind(); 
    second.rewind(); 
    int i; 
    for (i = 0; i < length-7; i+=8) { 
     if (first.getLong() != second.getLong()) { 
      return false; 
     } 
    } 
    for (; i < length; i++) { 
     if (first.get() != second.get()) { 
      return false; 
     } 
    } 
    return true; 
} 
-1

최대 스트림을 몇 메가 바이트로 설정해보십시오.

1

이 게시물에 링크 된 많은 기사가 실제로 구식 인 것으로 나타났습니다 (몇 가지 매우 통찰력있는 자료도 있음). 2001 년에 링크 된 기사가 있으며 정보는 의심 스럽습니다. 마틴 톰슨 (Martin Thompson)은 2011 년에 기계적인 동정심에 대해 이렇게 적었습니다.이 배경과 이론에 대해 그가 쓴 것을 참조하십시오.

NIO가 아닌지 NIO가 성능과 관련이 거의 없음을 발견했습니다. 그것은 출력 버퍼의 크기에 더 가깝습니다 (그 바이트 배열을 읽습니다). NIO는 빠른 웹 스케일 소스가 될 마술이 아닙니다.

나는 마틴의 예를 들고 1.0 시대의 OutputStream을 사용하여 비명을 지을 수있었습니다. NIO는 빠르지 만 가장 큰 지표는 출력 버퍼의 크기에 불과합니다. 물론 메모리 매핑 NIO를 사용하지 않는 한 NIO를 사용할지 여부는 중요하지 않습니다. 이에 대한 최신 권위있는 정보까지합니다 :)

마틴의 블로그를 참조하십시오 당신은 NIO이하지 않는 방법을보고 싶다면

http://mechanical-sympathy.blogspot.com/2011/12/java-sequential-io-performance.html

이 내가 할 수 있었다으로 (많은 차이 빠른 있었다 일반 IO를 사용하여 예제를 작성하는)이 참조 :

http://www.dzone.com/links/fast_java_io_nio_is_always_faster_than_fileoutput.html

나는 빠른 하드 디스크를 새 창 노트북에 내 가정을 테스트 한, SSD, EC2 내 맥북 프로 xlarge 및 최대 IOPS/고속 I/O (곧 대규모 디스크 NAS 파이버 디스크 어레이)의 EC2 4x 크기로 작동하므로 작동합니다 (EC2 인스턴스가 작을 때 문제가 있지만 성능에 신경 쓰는 경우). .. 작은 EC2 인스턴스를 사용 하시겠습니까?). 실제 하드웨어를 사용한다면 지금까지의 테스트에서 전통적인 IO가 항상 승리합니다. high/IO EC2를 사용하면 이것은 또한 확실한 승자입니다. Powered EC2 인스턴스에서 사용하면 NIO가 이길 수 있습니다.

벤치마킹 대신 사용할 수있는 것은 없습니다.

어쨌든, 저는 전문가가 아닙니다. 마틴 톰슨 경이 자신의 블로그 게시물에 쓴 프레임 워크를 사용하여 몇 가지 경험적 테스트를 수행했습니다.

나는 (심지어 작은 EC2 인스턴스에) 자바 I/O 비명을 만들기위한 조리법을 만들 TransferQueue와 (JDK 7에서)
Files.newInputStream 다음 단계로이를 데리고 을 사용했다. 조리법은 Boon (https://github.com/RichardHightower/boon/wiki/Auto-Growable-Byte-Buffer-like-a-ByteBuilder)의 설명서 맨 아래에 있습니다. 이것은 전통적인 OutputStream을 사용할 수있게 해주지 만 더 작은 EC2 인스턴스에서 잘 동작합니다. (저는 Boon의 주 저자입니다.하지만 새로운 저자를 받아들이고 있습니다. 시간당 0 달러가 지불되지만, 좋은 소식은 언제든지 지불 할 수 있습니다.)

2 센트입니다.

이유를 보려면 TransferQueue이 중요합니다.http://php.sabscape.com/blog/?p=557

주요 학습 :

  1. 성능에 대해 걱정하는 경우

    결코, 이제까지, 이제까지 의 BufferedOutputStream를 사용하지 않습니다.
  2. NIO가 항상 동일한 성능을 나타내는 것은 아닙니다.
  3. 버퍼 크기가 가장 중요합니다.
  4. 고속 쓰기를위한 재활용 버퍼가 중요합니다.
  5. GC는 고속 쓰기를 위해 성능을 저하시킬 수 있습니다.
  6. 사용한 버퍼를 다시 사용할 수있는 메커니즘이 있어야합니다.