2016-06-03 3 views
4

거대한 바이트 배열을 처리해야합니다. 이론 상으로는 멀티 코어 머신에서 성능을 높이기 위해 작업을 조각으로 나누어 다른 스레드에 할당 할 수 있어야합니다.멀티 스레드 ByteBuffers는 순차적으로 느립니까?

각 스레드에 대해 ByteBuffer을 할당하고 각각 데이터의 처리 된 부분을 할당했습니다. 8 개의 논리 프로세서가 있어도 최종 성능은 단일 스레드보다 느립니다. 또한 그것은 매우 일치하지 않습니다. 때로는 동일한 입력이 처리 속도가 느린 경우보다 두 배 이상 길 때가 있습니다. 왜 그런가요? 데이터가 먼저 메모리에로드되므로 더 이상 IO 작업이 수행되지 않습니다. 이 ByteBuffer.wrap()보다 빠른 때문에

나는 MappedByteBuffer를 사용하여 내 ByteBuffer의 할당 :

int threadsCount = Runtime.getRuntime().availableProcessors(); 
ExecutorService executorService = Executors.newFixedThreadPool(threadsCount); 
ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(executorService); 

for (ByteBufferRange byteBufferRange : byteBufferRanges) 
{ 
    Callable<String> task =() -> 
    { 
     performTask(byteBufferRange); 

     return null; 
    }; 

    completionService.submit(task); 
} 

// Wait for all tasks to finish 
for (ByteBufferRange ignored : byteBufferRanges) 
{ 
    completionService.take().get(); 
} 

executorService.shutdown(); 

동시 작업 performTask() 메모리를 읽고 자신의 ByteBuffer 인스턴스를 사용

public ByteBuffer getByteBuffer() throws IOException 
{ 
    File binaryFile = new File("..."); 
    FileChannel binaryFileChannel = new RandomAccessFile(binaryFile, "r").getChannel(); 

    return binaryFileChannel.map(FileChannel.MapMode.READ_ONLY, 0, binaryFileChannel.size()); 
} 

나는 Executors를 사용하여 내 동시 처리를 할 버퍼에서 계산 등을 수행합니다. 그들은 서로 동기화, 쓰기 또는 영향을주지 않습니다. 어떤 아이디어가 잘못되었거나 이것이 병렬화의 좋은 경우가 아닐까요?

ByteBuffer.wrap()MappedByteBuffer도 같은 문제가 있습니다.

+0

배열의 크기는 얼마나됩니까? – Logan

+1

매핑 된 버퍼는 실제로 파일이 메모리에로드되지 않습니다. OS는 파일 내용을 읽으면 파일 내용의 청크 (페이지)를 메모리에 동적으로 매핑하고 다른 곳에서 읽으면 다른 데이터에 대한 데이터를 바꿉니다. 메모리에 테라 바이트가있는 것처럼 보이지만 실제 메모리는 거의 사용하지 않습니다. 그러나 점프를하면 디스크에서 다시 읽어야 할 수도 있습니다. – zapl

+0

@LoganKulinski : 몇 가지 100MB – BullyWiiPlaza

답변

2

@EJP에서 언급했듯이 SSD가 도움이 될 수 있지만 실제로 디스크는 멀티 스레드가 아닙니다. 버퍼를 매핑하는 지점은 당신이 직접 메모리를 관리 할 필요가 없다. 가상 메모리 관리자와 파일 시스템 캐시가 Java 힙으로 이동하는 것보다 빠르기 때문에 작성한 메모리 관리 코드보다 더 빠를 것입니다.

처리가 실제로 병렬화 될 수 있다면, 단일 스레드가 전체 파일을 읽은 다음 (일부 중간 데이터 형식 일 수도 있음) 청크로 분할 한 다음 실행자가 이러한 청크에서 작업하는 것이 더 나을 것입니다. 파일 읽기 스레드는 다른 스레드와 동시에 실행할 수 있으므로 처리를 시작하려면 전체 파일을 읽을 필요가 없습니다.

파일 실행 스레드 수를 굶주 리지 않도록 cores - 1으로 설정하십시오. 이는 OS가 컨텍스트 스위칭없이 단일 코어에서 파일 읽기 스레드를 실행하는 기회를 제공하므로 다른 코어를 사용하여 CPU 집중적 인 작업을 수행하는 동안 우수한 IO 성능을 얻을 수 있습니다.

참고로 이것은 Apache Spark의 기본 사양입니다. 대용량 파일로 작업해야하거나 단일 시스템으로 수행 할 수있는 것보다 더 빨리 처리해야하는 경우이를 보길 원할 수 있습니다.