32

非常に簡単です: ConcurrentDictionary (必要に応じて使用しますが、実際には正しい概念ではありません) 以外に、アイテムまたは述語の単純な等価性に基づいて特定のアイテムの削除をサポートするコンカレント コレクション (IProducerConsumer 実装) はありますか?削除の条件を定義しますか?

説明: DB からオブジェクトをプルして「開始」キューに入れる、マルチスレッド、マルチステージのワークフロー アルゴリズムがあります。そこから、それらは次のステージに取り込まれ、さらに作業が行われ、他のキューに詰め込まれます。このプロセスは、さらにいくつかの段階を経て続きます。一方、最初のステージはそのスーパーバイザーによって再度呼び出され、オブジェクトを DB から引き出します。これらのオブジェクトには、まだ処理中のオブジェクトが含まれる可能性があります (処理が完了しておらず、次のように設定されたフラグで再永続化されていないため)。彼らは終わった)。

私が設計しているソリューションは、「作業中」のマスター コレクションです。オブジェクトは、最初のステージで処理のために取得されるとそのキューに入り、必要な処理を完了したワークフローのステージによって「処理済み」として DB に再保存された後に削除されます。オブジェクトがそのリストにある間、最初のステージで再取得された場合、オブジェクトは無視されます。

ConcurrentBag を使用する予定でしたが、唯一の削除方法 (TryTake) は、指定されたアイテムではなく、任意のアイテムをバッグから削除します (そして、.NET 4 ではConcurrentBag は低速で​​す)。ConcurrentQueue と ConcurrentStack では、次に提供されるアイテム以外のアイテムを削除することもできず、ConcurrentDictionary を残します。これは機能しますが、必要以上のものです (本当に必要なのは、処理中のレコードの ID を格納することだけです。ワークフロー中に変更されません)。

4

3 に答える 3

23

このようなデータ構造が存在しない理由は、すべてのコレクションが のルックアップ操作時間を持っているためですO(n)。などです。これらはすべてIndexOfRemove(element)すべての要素を列挙し、等しいかどうかをチェックします。

ハッシュ テーブルのみのルックアップ時間は O(1) です。並行シナリオでは、O(n) ルックアップ時間により、コレクションのロックが非常に長くなります。この間、他のスレッドは要素を追加できません。

辞書では、ハッシュにヒットしたセルのみがロックされます。他のスレッドは、ハッシュ セル内の要素の等価性をチェックしている間、追加を続けることができます。

私のアドバイスは、継続して ConcurrentDictionary を使用することです。


ちなみに、ConcurrentDictionary はソリューションに対して少し大きすぎるというのは正しいです。本当に必要なのは、オブジェクトが機能しているかどうかをすばやく確認することです。AHashSetはそれにぴったりです。その場合、基本的に何もしませんAdd(element), Contains(element), Remove(element). ConcurrentHeshSetJavaでの実装があります。c# の場合、次のことがわかりまし

HashSet最初のステップとして、インターフェイスを備えたラッパーを作成しConcurrentDictionaryて実行し、さまざまな実装を試してパフォーマンスの違いを確認します。

于 2012-07-27T21:21:33.460 に答える
6

すでに説明したように、他の投稿ではデフォルトでQueueまたはからアイテムを削除することはできませんConcurrentQueueが、実際に回避する最も簡単な方法は、アイテムを拡張またはラップすることです。

public class QueueItem
{
    public Boolean IsRemoved { get; private set; }
    public void Remove() { IsRemoved = true; }
}

そしてデキュー時:

QueueItem item = _Queue.Dequeue(); // Or TryDequeue if you use a concurrent dictionary
if (!item.IsRemoved)
{
    // Do work here
}
于 2015-01-24T20:47:54.383 に答える
1

一般的な意味でコレクションをスレッドセーフにするのは非常に困難です。ライブラリ/フレームワーククラスの責任または範囲外にあるスレッドセーフに入る非常に多くの要因があり、真に「スレッドセーフ」になる能力に影響を与えます...あなたが指摘した欠点の1つアウトはパフォーマンスです。最悪の事態を想定しなければならないため、スレッドセーフでもあるパフォーマンスの高いコレクションを作成することは不可能です...

一般的に推奨される方法は、任意のコレクションを使用し、スレッドセーフな方法でアクセスすることです。これが基本的に、フレームワークにスレッドセーフなコレクションがこれ以上ない理由です。詳細については、http://blogs.msdn.com/b/bclteam/archive/2005/03/15/396399.aspx#9534371を参照してください。

于 2012-07-27T21:20:34.913 に答える