2014-01-09 4 views
6

私は並列処理が必要な特定のアイテムのフローが一定であるため、TPL Dataflowを使用しています。キャッチは、同じキー(ディクショナリに似ています)を共有するアイテムは、FIFO順で処理され、互いに平行ではなく(異なる値を持つ他のアイテムと平行になることがあります)ということです。作業が行われてハッシュ/シャードされたActionBlocks

は、私の解決策はありません並列処理とEnvironment.ProcessorCountActionBlock<T> Sサイズの配列を作成し、キーの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を使用し、合計同時実行レベルを制限することができます。そのようなスケジューラin ParallelExtensionsExtrasまたはon MSDNを見つけることができます。

+0

これはどうやって悪いディストリビューションを解決しますか?私が他のものよりも多く使用される「特別な」ハッシュを持っている場合、 '%_actionBlocks.Length'を使用するのとは違った、多くのActionBlocksを互いにブロックする方法はありますか?あなたのケースの「特別な」ハッシュは、他のものと比較してキューを大きくします。 – i3arnon

+1

はい、それは他のものよりも大きくなりますが、ブロックの数が少ない場合よりも小さくなる可能性があります。その特別なハッシュとの衝突の数は少なくなります。たとえば、すべてのハッシュの半数が0で、残りが均等に分散されている場合、2つのブロックでは、すべてのアイテムの3/4がブロック0になります。ただし、4つのブロックでは、わずか5/8であり、 1/2になります。 – svick

+0

しかし、まだスレッドは2つしかありません。 1つは5/8ブロックと1/8ブロック(6/8 = 3/4)を処理し、もう1つのスレッドは2 1/8ブロックの左(2/8 = 1/4)を処理します。何か不足していますか? スレッド数を増やしても、このコードはCPUに非常に拘束され、コアあたりのAFAIKシングルスレッドが推奨されます。 – i3arnon

関連する問題