문제

NIO를 사용할 때 성능 (또는 장점)에 차이가 있는지 알아 내려고합니다. FileChannel 대 정상 FileInputStream/FileOuputStream 파일 시스템에 파일을 읽고 씁니다. 내 컴퓨터에서 둘 다 같은 수준에서 성능을 발휘하는 것을 관찰했습니다. FileChannel 길은 느립니다. 이 두 가지 방법을 비교 한 자세한 내용을 알 수 있습니까? 다음은 내가 사용한 코드입니다. 테스트중인 파일은 주변에 있습니다. 350MB. 무작위 액세스 또는 다른 고급 기능을보고 있지 않은 경우 파일 I/O에 NIO 기반 클래스를 사용하는 것이 좋습니다.

package trialjavaprograms;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class JavaNIOTest {
    public static void main(String[] args) throws Exception {
        useNormalIO();
        useFileChannel();
    }

    private static void useNormalIO() throws Exception {
        File file = new File("/home/developer/test.iso");
        File oFile = new File("/home/developer/test2");

        long time1 = System.currentTimeMillis();
        InputStream is = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(oFile);
        byte[] buf = new byte[64 * 1024];
        int len = 0;
        while((len = is.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        fos.flush();
        fos.close();
        is.close();
        long time2 = System.currentTimeMillis();
        System.out.println("Time taken: "+(time2-time1)+" ms");
    }

    private static void useFileChannel() throws Exception {
        File file = new File("/home/developer/test.iso");
        File oFile = new File("/home/developer/test2");

        long time1 = System.currentTimeMillis();
        FileInputStream is = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(oFile);
        FileChannel f = is.getChannel();
        FileChannel f2 = fos.getChannel();

        ByteBuffer buf = ByteBuffer.allocateDirect(64 * 1024);
        long len = 0;
        while((len = f.read(buf)) != -1) {
            buf.flip();
            f2.write(buf);
            buf.clear();
        }

        f2.close();
        f.close();

        long time2 = System.currentTimeMillis();
        System.out.println("Time taken: "+(time2-time1)+" ms");
    }
}
도움이 되었습니까?

해결책

더 큰 파일 크기에 대한 나의 경험은 그 일이었습니다 java.nio 보다 빠릅니다 java.io. 견고하게 더 빠릅니다. > 250% 범위와 마찬가지로. 즉, 나는 당신의 마이크로 벤치 마크가 고통받을 수 있다고 제안하는 명백한 병목 현상을 제거하고 있습니다. 조사를위한 잠재적 영역 :

버퍼 크기. 기본적으로 가지고있는 알고리즘은입니다

  • 디스크에서 버퍼로 복사하십시오
  • 버퍼에서 디스크로 복사하십시오

내 자신의 경험은이 버퍼 크기가 익은 튜닝을 위해. 나는 응용 프로그램의 한 부분에 대해 4KB에, 256KB를 위해 정착했습니다. 나는 당신의 코드가 큰 버퍼로 고통 받고 있다고 생각합니다. 1KB, 2KB, 4KB, 8KB, 16KB, 32KB 및 64KB의 버퍼로 일부 벤치 마크를 실행하여 자신에게 증명하십시오.

동일한 디스크를 읽고 쓰는 Java 벤치 마크를 수행하지 마십시오.

그렇게한다면, 당신은 Java가 아닌 디스크를 실제로 벤치마킹하고 있습니다. 또한 CPU가 바쁘지 않다면 아마도 다른 병목 현상을 경험하고 있다고 제안합니다.

필요하지 않은 경우 버퍼를 사용하지 마십시오.

대상이 다른 디스크 또는 NIC 인 경우 메모리에 복사하는 이유는 무엇입니까? 더 큰 파일의 경우, 인시 된 대기 시간은 사소하지 않습니다.

다른 사람과 마찬가지로 사용하십시오 FileChannel.transferTo() 또는 FileChannel.transferFrom(). 여기서 주요 장점은 JVM이 OS의 DMA 액세스를 사용한다는 것입니다.직접 메모리 액세스), 존재한다면. (이것은 구현 의존적이지만 범용 CPU의 현대 Sun 및 IBM 버전은 좋습니다.) 데이터는 디스크로, 버스로, 그리고 대상으로 바로 나오는 것입니다. RAM이나 CPU를 통해 회로를 우회합니다.

내가 낮과 밤을 보낸 웹 앱은 매우 무겁습니다. 마이크로 벤치 마크와 실제 벤치 마크도 마쳤습니다. 그리고 결과는 내 블로그에 올라가고 있습니다.

생산 데이터 및 환경을 사용하십시오

마이크로 벤치 마크는 왜곡되기 쉽다. 가능하다면, 당신이 기대하는 하드웨어에서 당신이 기대하는 하드웨어에서 정확히 할 계획에서 데이터를 수집하기 위해 노력하십시오.

저의 벤치 마크는 생산 시스템, 비프 시스템,로드 아래의 시스템, 로그로 수집 되었기 때문에 견고하고 신뢰할 수 있습니다. 아니다 JVM이 내 하드 디스크를 작동하면서 강렬하게 보는 동안 내 노트북의 7200 rpm 2.5 "SATA 드라이브.

당신은 무엇을 달리고 있습니까? 그것은 중요.

다른 팁

비교하려는 것은 파일 복사의 성능이라면 채널 테스트를 위해 대신이 작업을 수행해야합니다.

final FileInputStream inputStream = new FileInputStream(src);
final FileOutputStream outputStream = new FileOutputStream(dest);
final FileChannel inChannel = inputStream.getChannel();
final FileChannel outChannel = outputStream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
inputStream.close();
outputStream.close();

이것은 한 채널에서 다른 채널로 자신을 버리는 것보다 느리지 않으며 잠재적으로 훨씬 빠를 것입니다. Javadocs에 따르면 :

많은 운영 체제는 파일 시스템 캐시에서 실제로 복사하지 않고 대상 채널로 바이트를 전송할 수 있습니다.

내 테스트 (Win7 64bit, 6GB RAM, JAVA6)를 기반으로 NIO 전송은 작은 파일에서만 빠르며 큰 파일에서는 매우 느려집니다. NIO Databuffer Flip은 항상 표준 io를 능가합니다.

  • 1000x2MB 복사

    1. NIO (전송) ~ 2300ms
    2. NIO (직접 데이터베 버퍼 5000B 플립) ~ 3500ms
    3. 표준 IO (버퍼 5000B) ~ 6000ms
  • 100x20MB 복사

    1. NIO (직접 데이터베 버퍼 5000B 플립) ~ 4000ms
    2. NIO (전송) ~ 5000ms
    3. 표준 IO (버퍼 5000B) ~ 6500ms
  • 1x1000MB 복사

    1. NIO (Direct Datababuffer 5000B 플립) ~ 4500s
    2. 표준 IO (버퍼 5000B) ~ 7000ms
    3. NIO (전송) ~ 8000ms

TransferTo () 메소드는 파일 청크에서 작동합니다. 고급 파일 복사 방법으로 의도되지 않았습니다.Windows XP에서 큰 파일을 복사하는 방법은 무엇입니까?

질문의 "유용성"부분에 답하십시오.

사용의 다소 미묘한 gotcha FileChannel ~ 위에 FileOutputStream 차단 작업을 수행하는 것입니다 (예 : read() 또는 write())에있는 스레드에서 중단 된 상태 채널이 갑자기 닫히게됩니다 java.nio.channels.ClosedByInterruptException.

이제 이것은 무엇이든 좋은 일이 될 수 있습니다. FileChannel 스레드의 주요 기능의 일부가 사용되었으며 디자인이이를 고려했습니다.

그러나 벌목 함수와 같은 일부 보조 기능에서 사용하면 성가신 일 수도 있습니다. 예를 들어, 로깅 함수가 중단 된 스레드에 의해 호출되는 경우 로깅 출력이 갑자기 닫히는 것을 발견 할 수 있습니다.

불행히도 이것은 너무 미묘합니다. 이것을 설명하지 않으면 쓰기 무결성에 영향을 미치는 버그로 이어질 수 있기 때문입니다.[1][2]

Base64 인코딩 된 파일을 디코딩하기 위해 FileInputStream vs. Filechannel의 성능을 테스트했습니다. 내 경험에서 나는 다소 큰 파일을 테스트했으며 전통적인 IO는 NIO보다 조금 더 빠릅니다.

Filechannel은 여러 IO 관련 클래스에서 동기화 오버 헤드로 인해 이전 버전의 JVM에서 이점이 있었을 수도 있지만 최신 JVM은 불필요한 잠금을 제거하는 데 매우 능숙합니다.

Transferto 기능 또는 비 블로킹 기능을 사용하지 않는 경우 기존 IO가 NIO에 맵핑되기 때문에 전통적인 IO와 NIO (2)의 차이를 알지 못합니다.

그러나 TransferFrom/To와 같은 NIO 기능을 사용하거나 버퍼를 사용하려면 NIO가 갈 수 있습니다.

내 경험은 NIO가 작은 파일로 훨씬 빠르다는 것입니다. 그러나 큰 파일에 관해서는 FileInputStream/FileOutputStream이 훨씬 빠릅니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top