문제

저는 컴파일러, 최적화 프로그램 및 인덱싱 기술에 대해 자세히 알아보기 위해 C#으로 장난감 데이터베이스를 구축하고 있습니다.

페이지를 버퍼 풀로 가져오기 위한 요청(적어도 읽기) 간에 최대 병렬성을 유지하고 싶지만 .NET에서 이를 수행하는 가장 좋은 방법이 무엇인지 혼란스럽습니다.

다음은 제가 겪은 몇 가지 옵션과 문제입니다.

  1. 사용 System.IO.FileStream 그리고 BeginRead 방법

    그러나 파일의 위치는 다음의 주장이 아닙니다. BeginRead, 그것은 의 재산이다 FileStream (다음을 통해 설정 Seek 방법), 따라서 한 번에 하나의 요청만 실행할 수 있고 해당 기간 동안 스트림을 잠가야 합니다.(아니면 나도?내가 자물쇠 사이에만 자물쇠를 쥐고 있으면 어떤 일이 일어날지에 대한 문서가 불분명합니다. Seek 그리고 BeginRead 전화를 걸었지만 전화하기 전에 손을 뗐다 EndRead.아는 사람 있나요?) 이 방법을 알고 있지만 이것이 최선의 방법인지는 잘 모르겠습니다.

  2. 다른 방법이 있는 것 같습니다. System.Threading.Overlapped 구조 및 P\Invoke를 ReadFileEx kernel32.dll의 함수입니다.

    불행하게도 특히 관리되는 언어의 경우 샘플이 부족합니다.이 경로는 (작동할 수 있는 경우) 분명히 다음도 포함합니다. ThreadPool.BindHandle 메소드 및 스레드 풀의 IO 완료 스레드.나는 이것이 Windows에서 이 시나리오를 처리하는 승인된 방법이라는 인상을 받았지만 그것을 이해하지 못하고 초보자에게 도움이 되는 문서에 대한 진입점을 찾을 수 없습니다.

  3. 다른 것?

  4. 댓글에서 jacob은 새로운 것을 만들 것을 제안했습니다. FileStream 비행 중 각 읽기에 대해.

  5. 전체 파일을 메모리로 읽어옵니다.

    데이터베이스가 작은 경우에는 작동합니다.코드베이스는 작고 다른 비효율성도 많이 있지만 데이터베이스 자체는 그렇지 않습니다.또한 대규모 데이터베이스를 처리하는 데 필요한 모든 장부를 수행하고 있는지 확인하고 싶습니다. 이는 복잡성의 큰 부분을 차지합니다.페이징, 외부 정렬, ...) 그리고 실수로 속임수를 쓰기가 너무 쉬울까 걱정됩니다.

편집하다

해결 방법 1에서 의심스러운 이유를 설명합니다.BeginRead에서 EndRead까지 단일 잠금을 유지한다는 것은 다른 읽기가 진행 중이라는 이유만으로 읽기를 시작하려는 사람을 차단해야 함을 의미합니다.새로운 읽기를 시작하는 스레드는 결과가 제공되기 전에 (일반적으로) 더 많은 작업을 수행할 수 있기 때문에 잘못된 것 같습니다.(사실 이 글을 쓰면서 새로운 해결책이 생각나서 새로운 답을 내놨습니다.)

도움이 되었습니까?

해결책

우리가 한 일은 C++/CLI에서 I/O 완료 포트, ReadFile 및 GetQueuedCompletion 상태 주위에 작은 계층을 작성한 다음 작업이 완료되면 C#으로 다시 호출하는 것이었습니다.파일(또는 소켓)에서 읽는 데 사용되는 버퍼에 대한 더 많은 제어를 제공하기 위해 BeginRead 및 C# 비동기 작업 패턴 대신 이 경로를 선택했습니다.이는 각 읽기마다 힙에 새 바이트[]를 할당하는 순수 관리형 접근 방식에 비해 성능이 상당히 향상되었습니다.

또한 인터웹에는 IO 완료 포트를 사용하는 더 완전한 C++ 예제가 많이 있습니다.

다른 팁

옵션 1이 왜 효과가 없는지 잘 모르겠습니다.두 개의 서로 다른 스레드가 동시에 동일한 FileStream을 사용하려고 할 수 없다는 점을 명심하세요. 그렇게 하면 분명히 문제가 발생할 것입니다.BeginRead/EndRead는 잠재적으로 비용이 많이 드는 IO 작업이 수행되는 동안 코드가 계속 실행되도록 하기 위한 것이지 파일에 대한 일종의 다중 스레드 액세스를 활성화하기 위한 것이 아닙니다.

그래서 나는 당신이 찾고 나서 시작 읽기를 제안하고 싶습니다.

리소스(파일 데이터 등)를 먼저 메모리에 로드한 다음 스레드 간에 공유하면 어떻게 될까요?작은 db이기 때문입니다.- 처리할 문제가 많지 않을 것입니다.

접근법 #1을 사용하세요. 하지만

  1. 요청이 들어오면 A 잠금을 해제하세요.이를 사용하여 보류 중인 읽기 요청의 대기열을 보호합니다.이를 대기열에 추가하고 새로운 비동기 결과를 반환합니다.이로 인해 대기열에 첫 번째 추가가 발생하면 반환하기 전에 2단계를 호출하세요.돌아오기 전에 잠금 A를 해제하십시오.

  2. 읽기가 완료되면(또는 1단계에서 호출되면) 잠금 A를 사용합니다.대기열에서 읽기 요청이 팝업되는 것을 방지하는 데 사용합니다.잠금 B를 가져가세요.이를 사용하여 보호하십시오. Seek -> BeginRead -> EndRead 순서.잠금 B를 해제합니다.이 읽기 작업에 대해 1단계에서 생성된 비동기 결과를 업데이트합니다.(읽기 작업이 완료되었으므로 다시 호출하세요.)

이는 다른 읽기가 진행 중이기 때문에 읽기를 시작하는 스레드를 차단하지 않고 파일 스트림의 현재 위치가 엉망이 되지 않도록 계속해서 읽기 순서를 지정하는 문제를 해결합니다.

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