2011-05-08 3 views
3

나는 폴더 구조를 재귀 적으로 검색해야하는 프로그램을 작성 중이며 여러 스레드와 병렬로이를 수행하려고합니다.병렬로 큐를 처리하는 좋은 전략은 무엇입니까?

처음에는 큐에 루트 디렉토리를 추가 한 다음 디렉토리를 대기열에서 제외하고 하위 디렉토리를 대기열에 추가하는 등 대기열이 비어있을 때까지 이미 간단한 동기화 방법을 작성했습니다. 내 대기열에 ConcurrentQueue<T>을 사용할 것이지만 이미 내 루프가 너무 일찍 중단된다는 것을 깨달았습니다. 첫 번째 스레드는 루트 디렉토리를 대기열에서 제외하고 다른 모든 스레드는 대기열이 비어있는 것을보고 즉시 종료하여 첫 번째 스레드를 실행중인 유일한 스레드로 남겨 둡니다. 큐가 비어있을 때까지 각 스레드를 반복하고, 다른 스레드가 큐를 대기열에 추가 할 때까지 기다렸다가 계속 진행합니다. 모든 스레드가 루프의 끝에 도달 할 때까지 모든 스레드가 종료 될 수 있도록 일종의 검사 점이 필요합니다. 그러나 실제로 더 이상의 디렉터리가 없을 때 교착 상태없이이 작업을 수행하는 가장 좋은 방법은 아닙니다. 방법.

+0

폴더 구조에서 무엇을 검색 할 수 있습니까? fileName 또는 파일 안의 무엇인가? 아니면 다른 것? 나는 이것이 적절한 알고리즘으로 당신을 도우는 것이 중요하다고 생각합니다. –

+0

성능면에서 이점이 있습니까? 수천 개의 파일을 읽는 프로세스에서 비슷한 점을 살펴본 결과 제어 성능 요소가 디스크 IO이고 병렬 스레드에서의 처리가 성능에 큰 영향을 미치지 않는다는 것을 알게되었습니다. – ScruffyDuck

+0

정규식에 대해 디렉토리 이름 또는 파일 이름과 일치하는 결과를 반환합니다. 파일 내부의 내용과 일치하지 않습니다. 파일 속성을 확인하기 위해 확장 할 수도 있지만 그게 전부입니다. – dlras2

답변

5

Task Parallel Library을 사용하십시오.

첫 번째 폴더를 처리하려면 Task을 만듭니다. 이 경우 각 하위 폴더 (재귀 적으로)와 각 관련 파일에 대한 작업을 처리하기 위해 Task을 만듭니다. 그런 다음 wait on all이 폴더에 대한 작업.

TPL 런타임은 스레드 풀을 사용하지 않고 스레드 풀을 사용하므로 스레드가 비싼 작업입니다. 작은 작품들.

참고 :

  • 파일 당 작업이 사소한 경우 인라인 오히려 다른 작업을 만드는 것보다을 (IO 성능이 제한 요인이 될 것이다).
  • 이 방법은 일반적으로 차단 작업을 피할 때 가장 효과적 일 수 있지만 IO 성능이 제한적이라면 어쨌든이 문제는 중요하지 않을 수 있습니다. — 간단한 시작과 측정.
  • .NET 4 이전에는 스레드 풀을 사용하여 많은 작업을 수행 할 수 있었지만 작업 완료를 기다리는 데 events을 사용해야하고 대기하면 스레드 풀 스레드가 연결됩니다.

    1 내가 알고있는 것처럼


1 는 TPL에 대기이 충족 될 때까지 다른 작업 스레드를 재사용하는 TPL 방법 — TPL을 사용하여 작업 —에 기다릴 때.

+0

이것이 올바르게 이해된다면 하위 디렉토리를 대기열에 넣는 대신 명시 적 대기열을 모두 버리고 작업을 호출하겠습니까? – dlras2

+0

@ 대니얼 : 예. 명시 적 대기열을 암시 적 대기열 (스레드 풀의 작업 항목 대기열)로 대체하는 것이 좋습니다. – Richard

+0

이 방법으로 만난 문제는 모든 작업을 기다리는 방법을 모르겠다는 것입니다. 'WaitAll'은 대기 할 작업리스트를 필요로합니다. 각 작업은 더 많은 작업을 생성하기 때문에 기다리지 않아도됩니다. – dlras2

1

이 경우 가장 좋은 방법은 하위 디렉토리를로드 할 때마다 하나의 스레드를 만들어 스레드 풀에서 처리하여 스레드를 처리하는 것입니다. 스레드가 완료되면 스레드를 종료하고 디렉토리에서 한 단계 더 나아갈 때마다 풀에서 새 스레드를 호출하십시오. 이렇게하면 교착 상태가 발생하지 않고 시스템에서 필요한만큼 스레드를 사용합니다. 발견 된 폴더 수에 따라 시작할 스레드 수를 지정할 수도 있습니다.

편집 : 명시 적으로 새 스레드를 만들고 싶지 않지만 대신 스레드 풀을 사용하여 오버 헤드없이 필요에 따라 스레드를 추가 및 제거하고자한다고 위의 변경 사항을 변경했습니다.

+1

명시 적으로 스레드를 만드는 것은 거의 항상 잘못된 대답입니다. 스레드 풀 또는 작업이 더 잘 작동합니다. – Richard

+0

이것에 대해 생각했지만 모든 스레드를 만드는 오버 헤드가 이점보다 큽니까? 파일이나 디렉토리를 매칭하는 것은 어려운 일이 아니며 통과하기 위해서는 많은 것들이있을 수 있습니다. – dlras2

+0

@ 리차드 - 예, 필요하면 스레드 풀을 사용합니다. 나는 이것을 올렸을 때 나는 분명하지 않다고 생각했다. 아니요. 새로운 스레드를 처음부터 만들지는 않을 것입니다. 대신 스레드 풀에서 스레드를 꺼내서 끝내면 다시 돌아갈 수 있습니다. – IAmTimCorey

1

명시 적 대기열의 개념을 고수하려면 BlockingCollection 클래스를 살펴보십시오.메서드 GetConsumingEnumerable()은 컬렉션에 항목이 부족하여 새 항목을 사용할 수있을 때까지 계속할 때 차단하는 IEnumerable을 반환합니다. 즉, 콜렉션이 비어있을 때마다 스레드가 차단되어 조기 중지를 방지합니다.

그러나 기본적으로 이것은 생산자 - 소비자 시나리오에 매우 유용합니다. 귀하의 문제가이 범주에 속하는지 확실하지 않습니다.

+0

이것은 좋은 발견이지만 다른 제작자가 생산하는 한 생산자가 결정을 내릴 수 없다는 점에서 많은 제작자가 많은 소비자 시나리오에 적응하는 데 약간의 어려움이 있습니다. – dlras2

관련 문제