2014-09-30 1 views
3

인덱스 된 작업 집합을 처리하기 위해 Visual Studio 2010의 PPL (Parallel Patterns Library)의 Concurrency::parallel_for()을 사용하고 있습니다. 일반적으로 인덱스 집합은 동시에 실행할 수있는 스레드). 긴 계산을하기 전에 각 작업은 공유 자원 관리자에게 개인 작업 저장소 자원을 요청하여 시작합니다 (경우에 따라 작업 별 메모리 맵 파일에 대한보기가 있지만 각 작업이 같을 경우 스토리 라인이 같을 것이라고 생각합니다. 공유 힙에서 개인 메모리 할당을 요청했습니다).Concurrency :: parallel_for (PPL)에서 너무 많은 스레드가 생성되고 있습니다.

공유 리소스 관리자의 사용은 Concurrency::critical_section과 동기화되며 여기에서 문제가 시작됩니다. 첫 번째 스레드/작업이 중요 섹션에 있고 두 번째 작업이 요청을하면 첫 번째 작업의 요청이 완료 될 때까지 대기해야합니다 처리됩니다. PPL은 다음과 같이 생각합니다 :이 스레드가 대기 중이고 더 많은 작업이 필요하므로 다른 스레드가 생성되어 최대 870 개의 스레드가 대부분 동일한 자원 관리자에서 대기하게됩니다.

자원 요청을 처리하는 것이 전체 작업 중 일부에 지나지 않기 때문에 해당 부분의 PPL에게 말을 걸라고 말하고 싶습니다. 대기 또는 협동 블록으로 인해 새 스레드가 여기 작업 스레드의 표시된 부분 및 내 질문은 다음과 같습니다. 특정 스레드 섹션에서 새 스레드를 만들지 못하게 할 수있는 경우, 협력하여을 차단하더라도 마찬가지입니다. 스레드의 처리 경로를 따라 다른 블록에 새로운 스레드를 만들지는 않겠지 만 2 * (하이퍼) 코어의 개수는 말할 필요가 없습니다. 내가 지금까지 고려했다

대안 :

  1. 큐 업 작업과 스레드의 제한된 수의 큐를 처리합니다. 문제 : PPL의 parallel_for가 그 일을 직접 수행 할 수 있기를 바랍니다.

  2. Concurrency::combinable<Resource> resourceSet; Concurrency::parallel_for 외부에서 resourceSet.local()을 한 번 초기화하면 리소스를 재사용하여 리소스 요청 수를 스레드 수 (작업 수보다 적어야 함)로 줄입니다. 문제 :이 최적화로 인해 불필요한 스레드 생성이 방지되지 않습니다.

  3. parallel_for 루프 외부의 각 작업에 필요한 리소스를 미리 할당하십시오. 문제 : 너무 많은 시스템 리소스를 요청하는 반면 자원의 양은 스레드/코어의 수를 제한하는 것이 OK 일 것입니다 (폭발하지 않은 경우).

나는 http://msdn.microsoft.com/en-us/library/ff601930.aspx이 절에서는 "병렬 루프에서 반복적으로 차단하지 않음"읽을 수 있지만 전혀 병렬 스레드 초래 여기에 조언을 다음과 같습니다.

+0

(... 다시 예를 높일 수)는 x가 boost::thread::hardware_concurrency()이다 병렬에서 작업 'X'작업보다는 더 이상 없을 것입니다 보장, 당신의 작품 큐를 채워 HTTP : //stackoverflow.com/questions/9990363/thread-ids-with-ppl-and-parallel-memory-allocation? rq = 1 이것은이 질문과 매우 비슷합니다. –

답변

3

협업 동기화를 사용하지 않거나 적어도 작성한 스레드 수에 제한을두기 위해 PPL/ConcRT를 구성 할 수 있는지 여부는 알 수 없습니다. 나는 그것이 scheduler policies을 통해 제어 될지도 모른다고 생각했지만, 정책 매개 변수 중 아무 것도 그 목적에 맞지 않습니다.

  • 대신 critical_section, 자원 관리자를 보호하기 위해 기본이 아닌 협력 동기화를 사용하더라도 이상적인 방법으로하지 않으면

    난 당신이 문제를 완화하는 것이 유용 할 수있는 몇 가지 제안을하지만

    . 나는 고전적인 WinAPI CRITICAL_SECTION가 성공해야한다고 생각한다. 이 방향의 급진적 인 단계로서, 코드를위한 다른 병렬 라이브러리를 고려할 수 있습니다. 예 : Intel's TBB provides most of PPL API and has more (면책 조항 : 관련이 있습니다.)

  • 병렬 루프 외부에 많은 리소스를 사전 할당하십시오. 작업 당 하나의 리소스가 필요하지 않습니다. 스레드 당 하나씩 충분해야합니다. 이러한 리소스를 concurrent_queue에 넣고 작업에서 대기열의 리소스를 팝하고 사용하고 다시 밀어 넣습니다. 또한 리소스를 대기열로 반환하는 대신 스레드가 다른 작업에서 다시 사용할 수 있도록 combinable 객체 내부에 저장합니다. 대기열이 비어있는 경우 (예 : PPL이 시스템을 초과 구독하는 경우) 다른 접근 방식이있을 수 있습니다. 다른 스레드가 자원을 반환 할 때까지 루프에서 회전하거나 관리자에게 다른 자원을 요청할 수 있습니다. 또한 자원 고갈 가능성을 최소화하기 위해 스레드 수보다 많은 자원을 사전 할당하도록 선택할 수도 있습니다.

+0

감사합니다. 비 협력적인 동기화 (리소스 관리자는 협업 동기화가 필요한 다른 환경에서도 사용됨), TBB 및 boost :: thread를 고려하고 테스트 할 것입니다. –

+0

나는 큐가 비어있을 때 새로운 스레드를 시작하고 (협동하여) 블로킹을하고 다른 태스크는 여전히 시작을 기다리고 있다고 생각한다. –

+0

'concurrent_queue'에는 pop poping 메서드가 없습니다. 큐가 비어 있으면 즉시 반환하는'try_pop()'만 있습니다 (http://msdn.microsoft.com/en-us/library/ee355358.aspx 참조). 예. 성공할 때까지'try_pop()'을 호출하는 회전 루프를 만든다. –

1

내 대답은 PPL을 사용하여 "는"해결책이 아니다,하지만 난 당신이 taskqueue 같은 스레드 풀에 그렇게 쉽게 그것을 할 수 있다고 생각, 당신은 this answer에보고해야한다.

그래서 난 그냥 발견

+0

감사합니다. parallel_for가없는 것 같지만 boost :: threads를 다시 한 번 볼 것입니다. 따라서 작업 세트를 제한된 범위의 작업 범위로 나눠야 할 것입니다. –

관련 문제