2013-02-23 2 views
3

Windows 응용 프로그램에서 파일 이름과 버퍼를 래핑하는 클래스가 있습니다. 파일 이름을 사용하여 생성하고 객체를 쿼리하여 버퍼가 아직 채워져 있는지 확인하고, 그렇지 않으면 nullptr을 반환하고, 그렇지 않으면 버퍼 addres를 반환 할 수 있습니다.겹친 IO 또는 파일 매핑?

class file_buffer 
{ 
public: 
    file_buffer(const std::string& file_name); 
    ~file_buffer(); 
    void* buffer(); 

private: 
    ... 
} 

내가 비동기 메모리에 데이터를 넣어 원하고, 지금까지의 내가 그것을보고 나는 두 가지 선택이 있습니다 : 개체가 범위를 벗어날 경우, 버퍼는 해제 중 버퍼를 생성하고 사용 IO를 중복 ReadFileEx를 사용하거나 MapViewOfFile을 사용하고 다른 스레드의 주소를 터치하십시오.

현재 약 16MB보다 큰 요청이 실패하기 때문에 몇 가지 문제가있는 ReadFileEx를 사용하고 있습니다. 요청을 분할하려고 시도 할 수는 있지만 동기화 문제가 발생하고 개체가 범위를 벗어나는 경우 IO가 완료되기 전에 버퍼 정리 문제가 있습니다. 또한 클래스의 여러 인스턴스가 빠르게 연속해서 생성되는 경우 상황이 매우 까다 롭습니다.

다른 스레드의 데이터를 매핑하고 만지는 것은 상 한계 문제가 없으므로 상당히 쉬워 보입니다. 클라이언트가 절대적으로 데이터를 가져야 만하는 경우에는 주소를 간접 참조 할 수 있습니다. OS는 페이지 폴트에 대해 걱정하고 블로킹 히트를 취한다.

이 응용 프로그램은 단일 코어 컴퓨터를 지원해야하므로 제 질문은 다른 소프트웨어 스레드의 페이지 오류가 현재 스레드의 IO가 겹친 것보다 더 비쌉니까? 그들은 그 과정을 멈출 것인가? 중첩 된 입출력은 같은 방식으로 프로세스를 정지 시키거나 이해가 안되는 OS 매직이 있습니까? 페이지 중복은 중복 된 입출력을 사용하여 수행됩니까? http://msdn.microsoft.com/en-us/library/aa365199(v=vs.85).aspx (파일 관리 IO 개념) http://msdn.microsoft.com/en-us/library/windows/desktop/aa366556(v=vs.85).aspx (파일 매핑) 을하지만 성능 트레이드 오프를 만드는 방법을 추론 할 수없는 것 :

나는이 주제의 좋은 읽기 했어.

+2

우우! 나는 텀블 위드 배지를 가지고있다. 어쩌면 내가 C++ 태그를 추가해야합니다 ... – hatcat

답변

11

당신은 메모리 매핑 된 파일로 가고 싶어 결정적으로합니다. 오버랩 된 IO (FILE_FLAG_NO_BUFFERING)는 수년 동안 어떤 사람들에 의해 "RAM에 데이터를 저장하는 가장 빠른 방법"으로 옹호되어 왔지만 이것은 매우 특정한 상황에서 매우 contrieved 한 경우에만 해당됩니다. 정상적인 평균의 경우 버퍼 캐시를 끄는 것이 심각한 반 최적화입니다.

지금, FILE_FLAG_NO_BUFFERING이 중복 IO의 모든 단점을 가지고 있으며, 약 50 % 느린 (나는 아직도 이해할 수없는 이유에 대한)입니다없이 IO 을 중복.

다소 광범위한 벤치마킹을 수행했습니다. a year ago. 최종선은 : 메모리 매핑 된 파일은 더 빠르고, 더 좋고, 덜 놀랍습니다.

오버랩 된 IO는 버퍼 캐시를 사용할 때 훨씬 더 많은 CPU를 사용하며, 비동기식으로 잘 문서화되어 있고 문서화되지 않은 일부 조건 (예 : 암호화, 압축 및 순수 ... 요청 크기? 요청?), 예측할 수없는 시간에 응용 프로그램을 정지시킵니다.
요청을 제출하는 데 때때로 "우스운"시간이 걸릴 수 있으며 CancelIO은 가끔 취소하지 않고 완료 될 때까지 대기합니다. 미해결 요청을 처리하는 프로세스는 어렵습니다. 중복되지 않는 겹쳐진 쓰기로 버퍼를 관리하는 것은 그리 중요하지 않은 추가 작업입니다.

파일 매핑이 작동합니다. 풀 스톱. 그리고 그것은 잘 작동합니다. 놀라움도 재미도 없습니다. 모든 페이지를 건 드리면 오버 헤드가 거의없고 디스크가 제공 할 수있는 속도로 빠르게 전달되며 버퍼 캐시를 활용합니다. 싱글 코어 CPU에 대한 걱정은 아무런 문제가되지 않습니다. 터치 스레드가 오류가 발생하면 차단되고, 스레드가 차단되면 항상 다른 스레드가 CPU 시간을 얻습니다.

필자는 쓰기 바이트 수 이상이 될 때마다 으로 파일 매핑을 사용하여을 작성하고 있습니다. 이것은 다소 사소한 일이지만 (파일과 매핑을 수동으로 늘리거나 미리 할당해야하며 닫을 때 실제 길이로 잘라야 함) 일부 도우미 클래스에서는 전적으로 수행 할 수 있습니다. 500 MiB의 데이터를 쓰면 "0 시간"(기본적으로 memcpy입니다. 실제 쓰기는 프로그램이 끝난 후에도 언제든지 백그라운드에서 수행됩니다). 운영 체제가 수행하는 것이 자연 스럽다는 것을 알고 있더라도 이것이 얼마나 효과적인지는 놀랍습니다.
물론 OS가 모든 페이지를 작성하기 전에 전원 장애가 발생하지 않는 것이 더 좋았지 만 모든 종류의 글에 해당됩니다. 디스크에없는 것은 무엇입니까? 은 디스크에 없습니다 - 그 이상은 말할 것도 없습니다. 확실하게 알고 싶다면 디스크 동기화가 완료 될 때까지 기다려야합니다. 그러면 동기화가 완료 될 때까지 번등이 꺼지지 않을 지 알 수 없습니다.. 인생이 다 그렇지.

4

나는 발명품을 만든 것처럼 보이지만이 점을 당신보다 더 잘 이해한다고 주장하지 않습니다. 그리고 실험을해야 할 것입니다. 하지만이 문제에 대한 이해는 역순입니다 :

  1. 파일 매핑 및 Windows에서 다른 implentations을 IO를하는 중복 및 그들 중 누구도 후드에서 다른 에 의존하지 않습니다. 그러나 둘 다 비동기 블록 장치 계층을 사용합니다. 상상할 수 있듯이 커널에서 IO는 실제로 비동기식이지만 일부 사용자 작업은 완료 될 때까지 기다리므로 동기화 성이라는 환상을 만듭니다.
  2. 지점 1에서 스레드가 IO를 수행하는 경우 동일한 프로세스의 다른 스레드가 이 아니며이 중지됩니다. 즉, 시스템 리소스가 부족하거나 다른 스레드가 IO를 수행하고 어떤 종류의 경합에 직면하지 않는 한. 첫 번째 쓰레드가하는 IO의 종류에 상관없이 블로킹, 비 블로킹, 오버랩, 메모리 맵핑이 가능하다.
  3. 메모리 매핑 된 파일에서 한 번에 한 페이지 씩, 적어도 미리 읽기 때문에 더 많은 데이터가 읽혀 지지만 확실하지는 않습니다. 따라서 탐색 스레드는 모든 페이지에서 최소한 하나의 매핑 된 메모리를 터치해야합니다. 그것은 probe/block-probe-probe-probe-probe/block-probe와 같을 것입니다. 이것은 몇 MB의 큰 overlapped read보다 약간 덜 효율적일 수 있습니다. 아니면 커널 프로그래머가 똑똑하고 더 효율적일 수도 있습니다. 당신은 약간의 프로파일 링을해야 할 것입니다 ... 이봐 요, 당신도 탐사 스레드없이 갈 수있는 일이 어떻게 볼 수 있습니다.
  4. 중복 작업 취소는 PITA이므로 메모리 매핑 파일을 사용하는 것이 좋습니다.즉 설정하는 방법 쉽게 그리고 당신은 추가 기능 얻을 : 메모리가 사용할 수
    1. 는 메모리가있는 경우 메모리
    2. 메모리가/프로세스의 여러 인스턴스가 공유 될 수
    3. 완전히에도 이전을 캐시에 저장되어 있으면 바로 그 대신 즉시 준비가됩니다.
    4. 데이터가 읽기 전용 인 경우 메모리에서 쓰기를 방지하고 버그를 잡을 수 있습니다.
+0

입력 해 주셔서 감사합니다; 그것은 상황에 대한 나의 생각과 일치합니다.메모리 매핑 방식을 선호하지만 디버깅을 마쳤으며 코드를 테스트하고 대체품을 판매하려면 성능이 향상되어야합니다. – hatcat

+0

@hatcat : 아직 파일을 사용하고 있지 않다면 파일을 열 때'FILE_FLAG_SEQUENTIAL_SCAN'을 사용하려고 할 수 있습니다. overlapped 및 mmaped IO의 성능을 향상시킬 수 있습니다. – rodrigo