2014-01-09 3 views
6

내가 병렬 처리해야하는 특정 항목의 일정한 흐름을 가지고 있으므로 TPL Dataflow을 사용하고 있습니다. catch와 같은 키를 공유하는 항목 (사전과 유사)은 FIFO 순서로 처리되어야하며 서로 평행하지 않아야합니다 (서로 다른 값을 가진 다른 항목과 병렬이 될 수 있음). 작업이 진행되고해쉬 된/Sharded ActionBlocks

내 솔루션은 더 병렬 처리 Environment.ProcessorCountActionBlock<T>의 크기의 배열을 생성하고 키의 GetHashCode 값에 따라 그들에 게시했다 그래서 최소한의 비동기 잠금 장치와 결합 된 매우 CPU입니다.

창조 :

_actionBlocks = new ActionBlock<Item>[Environment.ProcessorCount]; 
for (int i = 0; i < _actionBlocks.Length; i++) 
{ 
    _actionBlocks[i] = new ActionBlock<Item>(_ => ProcessItemAsync(_)); 
} 

사용법 :

그래서
bool ProcessItem(Key key, Item item) 
{ 
    var actionBlock = _actionBlocks[(uint)key.GetHashCode() % _actionBlocks.Length]; 
    return actionBlock.Post(item); 
} 

, 내 질문은,이 내 문제에 대한 최선의 해결책인가? 성능/확장성에 문제가 있습니까? 내가 놓친 게 있니?

+1

나는 그것을 좋아한다. 나는 저장을 필요로하지 않을 다른 방법을 생각할 수 없다. 나는 당신이 해쉬 코드가 적절히 배포되었는지를 확인하는 한, 이것은 괜찮을 것이라고 생각한다. – spender

+0

'GetHashCode'의 값에 의존하는 것은 나에게 아주 이상하게 들립니다. 왜 그걸 가지고 있습니까? 실제 요구 사항 "동등한 항목을 FIFO 순서로 처리해야합니까?" – svick

+0

@svick 같은 키를 가진 항목은 사전을 사용하는 것과 비슷한 FIFO 순서로 처리되어야합니다 (실제로는 같은 항목 유형 일 필요는 없습니다). 나는 그것을 명확하게하기 위해 질문을 업데이트 할 것이다. – i3arnon

답변

3

해시 코드가 잘 분산되어 있다는 것을 알고 있다고 가정 할 때 귀하의 접근 방식은 합리적이라고 생각합니다.

나쁜 배포를보다 잘 보호하려면 ActionBlock을 더 많이 사용하면서 모든 블록에서 단일 사용자 정의 TaskScheduler을 사용하여 총 동시성 수준을 제한 할 수 있습니다. 그러한 스케줄러 in ParallelExtensionsExtras 또는 on MSDN을 찾을 수 있습니다.

+0

어떻게 나쁜 배포판을 해결할 수 있습니까? 다른 사람들보다 더 많이 사용되는 "특별한"해시가 있다면, 어떻게 서로를 막는 많은 ActionBlock을 '% _actionBlocks.Length'와 다른 방식으로 사용합니까? 귀하의 경우에 "특별한"해시는 다른 것들과 관련하여 큐를 더 크게 만들 것입니다 ... – i3arnon

+1

그래, 여전히 다른 것보다 크지 만 블록의 수가 적을 때보 다 작을 것입니다. 해당 특수 해시와의 충돌 수가 더 적습니다. 예를 들어, 모든 해시의 절반이 0이고 나머지가 균등하게 분산 된 경우 2 블록으로 모든 항목의 3/4이 블록 0으로 이동합니다. 그러나 4 블록의 경우 5/8이고 무한 블록의 경우 1/2이 될 것입니다. – svick

+0

하지만 여전히 스레드는 2 개뿐입니다. 하나는 5/8 블록과 1/8 블록 (6/8 = 3/4)을 처리하고 다른 스레드는 2 1/8 블록을 처리합니다 (2/8 = 1/4). 내가 놓친 게 있니? 스레드 수를 늘리면이 코드가 매우 CPU 바운드이고 코어 당 AFAIK 단일 스레드가 권장됩니다. – i3arnon