2016-12-21 1 views
7

고정 된 청크 8192 바이트로 제공되는 큰 바이너리 파일 (4 ~ 6GB)을 읽거나 파싱해야합니다. 현재 솔루션에는 SPMC (Single Producer Multiple Consumer) 패턴을 사용하여 파일 청크를 스트리밍하는 작업이 포함됩니다.멀티 스레드 파일 읽기

편집

파일 크기 = N * 8192 바이트

내가 필요하고 모든이 8192 바이트의 각 무언가를하는 것입니다. 파일은 맨 아래로 한 번만 읽어야합니다.

는 (파일 크기/ X)은 독립적으로 크기, 내가 동등한 거리에서 읽을 수 X 스레드를하고 싶은이 황당 병렬 문제가되어야한다고 생각 데. 쓰레드는 서로 통신 할 필요가 전혀 없습니다.

내가 같은 파일을 열고 처리하는 각각의 섹션을 추구하는 산란 X 스레드를 시도했다, 그러나,이 솔루션은 노력과 분명히보다 더 수행 HDD 기계에 의한에 문제가있는 것 SPMC 솔루션

이 방법을 SSD에서 대신 사용하면 어떤 차이가 있습니까?

아니면 전체 파일을 메모리 맵으로 매핑하고 청크를 처리하기 위해 #pragma omp parallel for을 사용 하시겠습니까? 이 작업을 수행하기에 충분한 RAM이 필요할 것이라고 생각하십니까?

무엇을 제안하겠습니까?

+0

파일의 구문과 형식에 대해 충분히 알지 못합니다. –

+1

이 바이너리 파일은 N * 8192 바이트이고이 8192 바이트 각각에 대해 개별적으로 작업해야합니다. –

+2

[여기] (http://stackoverflow.com/a/41237690/841108)에 언급 된 시스템 호출 (Linux OS라고 가정)이 도움이 될 수 있습니다. 하지만 병목 현상은 디스크 자체라고 생각합니다. 당신은 아마 너무 많은 쓰레드를 원하지 않을 것입니다. (그래서 * X *는 4에서 10이 될 것이고 많지는 않습니다.) 벤치마킹해야합니다. 하드웨어 디스크가 한 번에 단 하나의 요청 만 처리 할 수 ​​있기 때문에 당황스럽지 않은 병렬 문제는 아닙니다. –

답변

5

무엇을 제안하겠습니까?

사람들의 mmap()와 복사 작업을 최적화 할 에 페이지 테이블 함께 플레이하는 다른 방법을 사랑하고, 때로는 :

mmap()

Linux Torvalds himself 당 사용하지 마십시오 그만한 가치가 있습니다.

그러나 가상 메모리 매핑을 사용하여 게임을하는 것은 매우 비싸다. . 사람들은 메모리 복사가 매우 느린 것으로 보이고 때로는 복사를 최적화하는 것이 명백한 improvment로 간주되기 때문에 많은 사람들이 무시하는 경향이있는 매우 실제적인 단점이 있습니다. mmap에에

단점 :

  • 매우 눈에 띄는 설치 및 해체 비용. 그리고 나는 두드러진을 의미합니다. 페이지 테이블을 따라 모든 것을 깨끗하게 해제하는 것과 같습니다. 모든
    매핑의 목록을 유지 관리하는 것은 책 관리입니다. TLB 플러시가 매핑 해제 된 후에 필요합니다.
  • 페이지 폴트가 비싸다. 이것이 매핑이 채워지는 방식이며, 매우 느립니다. mmap에의

그나 :

그냥 뭔가를 매핑하여 다른 많은 로직을 피할 수 있다면 데이터를 통해 재사용 및 다시 (단일지도 작업 이내), 또는 도착하면
  • mmap()은 슬라이스 된 빵 이후로 가장 좋은 것입니다.

이 파일은 여러 번 실행되는 파일 일 수 있습니다 (실행 파일의 이진 이미지가 여기에 표시됩니다 - 코드가 모든 위치로 점프합니다). 또는 mmap()이 단지이기는 실제 사용 패턴에 관계없이 모든 것을 포함합니다. 무작위 액세스 패턴이있을 수 있으며 실제로 필요한 데이터를 추적하는 방법으로 mmap()을 사용합니다.

  • 데이터가 큰 경우 mmap()은 데이터 세트로 수행 할 수있는 작업을 시스템에 알리는 좋은 방법입니다. 커널은 메모리 부족으로 시스템이 페이지를 빠져 나갈 때까지 페이지를 잊어 버릴 수 있으며, 자동으로 페이지를 다시 가져옵니다.

    자동 공유는 분명히이 경우입니다.

그러나 테스트 스위트 (한 번만 데이터를 복사가) mmap에 대한 아마 pessimal ()입니다.

마지막으로 - 데이터를 한 번 사용하면 mmap()의 잘못된 사용 사례임을 유의하십시오.하나의 int 파일 기술자를 얻을 수 open()를 사용하여 한 번

  1. 파일을 엽니 다 : 물리적 머리가 없기 때문에 SSD의에있는 파일에 대한

    는 움직임을 추구합니다.

  2. 스레드 당 pread()을 사용하여 적절한 8kB 청크를 읽습니다. pread()lseek()을 사용하지 않고 지정된 오프셋에서 읽으며 읽는 파일의 현재 오프셋에는 영향을주지 않습니다.

각 스레드에서 대기중인 상당한 IO가 있기 때문에 아마 CPU 코어보다 약간 많은 스레드가 필요할 것입니다. 기계 디스크 (들)에있는 파일에 대한

:

당신은 머리를 기계적 디스크 (들)을 추구 최소화하려는.

직접 IO를 사용하여 open() (Linux라고 가정)을 사용하여 파일을 한 번 엽니 다 (Linux를 가정 할 경우 open(filename, O_RDONLY | O_DIRECT);) 파일을 스트리밍 할 것이므로 파일의 일부를 다시 읽지 않으므로 페이지 캐시는 단일 생산자 스레드를 사용하여)

  1. 여기 좋은, 큰 덩어리 (1메가바이트 +에 64K 말) N 페이지 정렬 버퍼 중 하나에 을 읽을 수 없습니다.
  2. 버퍼가 읽어
  3. , 모든 근로자가 버퍼의 그들의 부분을 사용하여 수행하는 경우 그 다음 버퍼

  4. 을 채우기 위해 읽고, 작업자 스레드에 전달, 읽기 스레드에 다시 버퍼를 통과 .

당신은 적절한 read() 크기, 작업자 스레드의 수, 건네 버퍼의 수를 실험해야합니다

. 큰 read()이 더 효율적이지만 버퍼 크기가 클수록 메모리 요구량이 커지고 작업자 스레드에서 해당 버퍼를 가져 오는 대기 시간이 훨씬 더 예측할 수 없게됩니다. 가능한 한 적은 데이터 복사본을 만들고 싶기 때문에 작업자 스레드가 파일에서 읽은 버퍼에서 직접 작업하기를 원합니다.

+0

*의 전제는 mmap *을 사용하지 않습니다. 단지 * 한 번만 데이터를 사용하는 것 같습니다. 나는 그 질문을 읽지 않는다. – Zulan

+0

@ Zulan 파일에서 데이터를 두 번 이상 읽는다는 질문에서 읽은 위치를 설명 할 수 있습니까? –

+0

그 중 하나도 읽지 않습니다. 내가 읽은 것은 말 그대로 * "무언가를하는 것"*입니다. – Zulan

4

각 8K 블록의 처리가 중요하더라도 (OCR 처리 부족), 입출력이 병목 현상입니다. 이가 실행되는 시스템이 문제에 전념 할 수있는 경우가 .... 이미 이전 작업에 의해 캐시 할 파일의 부품

를 배치 할 수없는 한 :

  1. 파일 크기를 가져옵니다 (fstat)
  2. 해당 크기의 버퍼를 할당하십시오.
  3. 전체 파일을 열고 버퍼로 읽습니다.
  4. 스레드 당 데이터를 분할하고 스레드를 스핀 아웃하는 방법을 설명합니다.
  5. 시간 알고리즘.

그런 다음 비동기 읽기를 사용하여 수정하십시오. 수행해야 할 작업을 알아 보려면 man aio_readman 7 aio을 참조하십시오.

+1

이와 같은 파일을 읽으려면 가능한 경우 직접 IO를 사용하도록 추가하십시오. 이와 같이 처리하는 두 가지 단점은 1) 메모리 요구 사항 - 파일이 메모리에 적합해야하고 2) 대기 시간 - 전체 파일을 읽을 때까지 처리가 시작되지 않습니다. 그것은 확실히 가장 단순하고 유지하기 쉬운 접근법입니다. –

관련 문제