FileInputStream을 사용할 때 이상적인 버퍼 사이즈는 어떻게 결정합니까?
파일에서 MessageDigest(해시)를 작성하는 방법이 있는데, 많은 파일(>= 100,000)에 대해 작성해야 합니다.성능을 최대화하려면 파일에서 읽을 때 사용하는 버퍼 크기를 얼마나 크게 해야 합니까?
대부분의 사용자는 기본 코드를 잘 알고 있습니다(만일을 위해 여기서 다시 설명하겠습니다).
MessageDigest md = MessageDigest.getInstance( "SHA" );
FileInputStream ios = new FileInputStream( "myfile.bmp" );
byte[] buffer = new byte[4 * 1024]; // what should this value be?
int read = 0;
while( ( read = ios.read( buffer ) ) > 0 )
md.update( buffer, 0, read );
ios.close();
md.digest();
스루풋을 최대화하는 데 이상적인 버퍼 사이즈는 어느 정도입니까?이것은 시스템에 따라 다르며 OS, FileSystem, HDD에 따라 다르며 다른 하드웨어/소프트웨어가 섞여 있을 수 있습니다.
(Java를 처음 접하기 때문에 모르는 Java API 호출일 수도 있습니다.)
편집 : 사전에 어떤 시스템에서 사용할지 모르기 때문에 많은 것을 상정할 수 없습니다.(Java를 사용하고 있습니다.)
편집: 위의 코드에는 시도와 같은 항목이 누락되어 있습니다.기둥을 작게 하기 위해 잡다
최적의 버퍼 크기는 파일 시스템 블록 크기, CPU 캐시 크기 및 캐시 지연 시간 등 여러 가지와 관련이 있습니다.
대부분의 파일 시스템은 4096 또는 8192의 블록 크기를 사용하도록 구성되어 있습니다.이론적으로 디스크 블록보다 몇 바이트를 더 읽도록 버퍼 크기를 설정하면 파일 시스템에서의 조작이 매우 비효율적일 수 있습니다(즉, 버퍼를 4100바이트를 한 번에 읽도록 구성한 경우 파일 시스템에서 읽을 때마다 2개의 블록 읽기가 필요합니다).블록이 이미 캐시에 있는 경우 RAM -> L3/L2 캐시 지연에 대한 대가를 지불해야 합니다.운이 나쁘고 블록이 아직 캐시에 없는 경우 디스크>RAM 지연에 따른 대가도 지불됩니다.
따라서 대부분의 버퍼는 2의 거듭제곱으로 표시되며 일반적으로 디스크 블록 크기보다 크거나 같습니다.즉, 스트림 읽기 중 하나가 여러 개의 디스크 블록 읽기를 발생시킬 수 있지만 이러한 읽기에는 항상 전체 블록이 사용되므로 읽기가 낭비되지 않습니다.
일반적인 스트리밍 시나리오에서는 디스크에서 읽어낸 블록은 다음 번 읽기에 도달해도 메모리에 남아 있기 때문에(결국 여기서는 순차적으로 읽기를 하고 있습니다), 결과적으로 다음 읽기에 RAM -> L3/L2 캐시 레이텐시 값을 지불하게 됩니다만, 디스크 -> RAM 레이텐시는 지불하지 않습니다.디스크 > RAM의 레이텐시는 크기 면에서 매우 느리기 때문에 다른 레이텐시는 거의 없어집니다.
따라서 다른 캐시 크기를 사용하여 테스트를 실행한 경우(직접 실행하지 않음) 파일 시스템 블록 크기까지 캐시 크기가 큰 영향을 미칠 수 있습니다.그 이상으로, 나는 사태가 꽤 빨리 진정될 것이라고 생각한다.
여기에는 많은 조건과 예외가 있습니다.시스템의 복잡성은 실제로 매우 큽니다(L3 -> L2 캐시 전송 처리만 해도 매우 복잡하며 CPU 유형에 따라 달라집니다).
이를 통해 다음과 같은 '실제 세계'의 답이 나옵니다.앱이 99%인 경우 캐시 크기를 8192로 설정하고 다음으로 넘어갑니다(더 좋은 방법은 성능보다 캡슐화를 선택하고 Buffered Input Stream을 사용하여 세부 정보를 숨기는 것입니다).디스크 throughput에 크게 의존하는 1%의 애플리케이션을 사용하고 있는 경우, 다양한 디스크 상호 작용 전략을 교환할 수 있도록 구현하고, 사용자가 테스트 및 최적화할 수 있도록 노브와 다이얼을 제공합니다(또는 자체 최적화 시스템 제공).
네, 아마 여러 가지에 따라 다르겠지만 큰 차이가 있을지 의문입니다.메모리 사용량과 성능의 균형을 잘 맞추기 위해 16K 또는 32K를 선택하는 경향이 있습니다.
예외가 발생하더라도 스트림이 닫히도록 하려면 코드 내에서 시도/최종적으로 차단해야 합니다.
대부분의 경우, 그것은 그다지 중요하지 않습니다.4K나 16K 같은 적당한 사이즈를 골라 그대로 유지하세요.이것이 애플리케이션의 병목 현상이라고 확신하는 경우 최적의 버퍼 크기를 찾기 위한 프로파일링을 시작해야 합니다.너무 작은 사이즈를 선택하면 추가 I/O 작업과 추가 기능 호출에 시간을 낭비하게 됩니다.너무 큰 사이즈를 선택하면 캐시 누락이 많아져 속도가 느려집니다.L2 캐시 크기보다 큰 버퍼를 사용하지 마십시오.
이상적인 경우 한 번의 읽기 작업으로 파일을 읽을 수 있는 충분한 메모리가 있어야 합니다.시스템에서 파일 시스템, 할당 장치 및 HDD를 마음대로 관리할 수 있기 때문에 최고의 성능을 발휘합니다.실제로 파일 크기를 미리 알 수 있다면 4K(NTFS의 기본 할당 단위)까지 반올림된 평균 파일 크기를 사용하십시오.가장 좋은 것은 여러 옵션을 테스트하기 위한 벤치마크를 작성하는 것입니다.
Buffered Streams/reader를 사용한 후 버퍼 크기를 사용할 수 있습니다.
Buffered XStreams는 버퍼 사이즈로 8192를 사용하고 있다고 생각합니다만, Ovidiu가 말한 것처럼, 많은 옵션에 대해 테스트를 실시해야 할 것 같습니다.최적의 사이즈는 파일 시스템과 디스크 구성에 따라 달라집니다.
Java NIO의 FileChannel과 MappedByteBuffer를 사용하여 파일을 읽으면 FileInputStream과 관련된 어떤 솔루션보다 훨씬 빠른 솔루션이 될 수 있습니다.기본적으로 대용량 파일을 메모리 매핑하고 소형 파일에는 직접 버퍼를 사용합니다.
BufferedInputStream의 소스에는 private static int DEFAULT_BUFFER_SIZE = 8192;
따라서 기본값을 사용해도 됩니다.
하지만 더 많은 정보를 얻을 수 있다면 더 가치 있는 답변을 얻을 수 있을 것입니다.
예를 들어 adsl은 TCP/IP의 payload 때문에 1454바이트의 버퍼를 프리퍼할 수 있습니다.디스크의 경우 디스크의 블록 크기와 일치하는 값을 사용할 수 있습니다.
다른 답변에서 이미 설명한 바와 같이 Buffered Input Streams를 사용합니다.
그 후 버퍼 사이즈는 그다지 중요하지 않다고 생각합니다.어느 쪽이든 프로그램이 I/O에 바인딩되어 있기 때문에 BIS 기본값보다 버퍼 크기를 늘려도 성능에 큰 영향은 없습니다.
또는 프로그램이 MessageDigest.update() 내에 CPU가 바인드되어 있고 대부분의 시간이 응용 프로그램코드에서 사용되지 않기 때문에 조정해도 도움이 되지 않습니다.
(음... 코어가 여러 개인 경우 스레드가 도움이 될 수 있습니다.)
1024는 다양한 상황에 적합합니다만, 실제로는 버퍼 사이즈가 크거나 작을수록 퍼포먼스가 향상되는 경우가 있습니다.
이는 파일 시스템 블록 크기 및 CPU 하드웨어 등 여러 요소에 따라 달라집니다.
또한 대부분의 기본 하드웨어는 2의 거듭제곱인 플릿 블록과 캐시 크기로 구성되기 때문에 버퍼 크기로 2의 거듭제곱을 선택하는 것이 일반적입니다.Buffered 클래스를 사용하면 생성자에서 버퍼 크기를 지정할 수 있습니다.아무것도 제공되지 않은 경우 기본값을 사용합니다. 기본값은 대부분의 JVM에서 2의 거듭제곱입니다.
어떤 버퍼 크기를 선택하든 가장 큰 성능 향상은 비버퍼형 파일 액세스에서 버퍼형 파일 액세스로 이동하는 것입니다.버퍼 사이즈를 조정하면 퍼포먼스가 약간 향상되는 경우가 있습니다만, 극히 작거나 매우 큰 버퍼 사이즈를 사용하고 있지 않는 한 큰 영향은 거의 없습니다.
언급URL : https://stackoverflow.com/questions/236861/how-do-you-determine-the-ideal-buffer-size-when-using-fileinputstream
'itsource' 카테고리의 다른 글
vueJ2에 페이지 수가 있지만 렌더링하지 못한 요소-ui 테이블의 행에 대한 배경색 (0) | 2022.08.31 |
---|---|
C에서의 변수 선언 배치 (0) | 2022.08.31 |
등록된 모든 Vuex 모듈을 가져오는 방법 (0) | 2022.08.31 |
NuxtJs 응용 프로그램에서 Vue.set()을 사용하는 방법 (0) | 2022.08.31 |
$NON-NLS-1$의 의미는 무엇입니까? (0) | 2022.08.31 |