ConcurrentBagからすべてのアイテムを削除するにはどうすればよいですか?


回答:


37

競合状態の可能性があるため、完全にはクリアされない場合がありますが、これで十分です。

while (!myBag.IsEmpty) 
{
   myBag.TryTake(out T _);
}

23
これは間違いなくアトミックではありません。したがって、他のすべてのメソッドはアトミックアクセスを想定して使用されるため、ConcurrentBagの拡張メソッドとして追加しないでください。
アヌパム2013

また、TryTakeは、空以外の理由で失敗することはありませんか?
BrainSlugs83 2014

21
これは非常に危険です。別のプロセスが継続的にアイテムを追加している場合、これはビジー状態のままになる可能性があります。
ivoTops 2014年

4
@Adam Houldsworth +私のコメントからの回答の方が優れています。
Chris Marisic 2015

1
これが危険な解決策である場合、なぜそれがまだ受け入れられている答えなのですか?
バリスAkkurt

65

2017年10月3日更新: @Louが正しく指摘しているように、割り当てはアトミックです。この場合、の作成はConcurrentBagアトミックではありませんが、その参照を変数に入れることアトミックになります。したがって、ロックまたはInterlocked.Exchangeその周囲は厳密には必要ありません。

さらに読む:

参照の割り当てはアトミックですが、なぜInterlocked.Exchange(ref Object、Object)が必要なのですか?

参照割り当てはスレッドセーフですか?


バッグ自体へのアクセスをいつでもロックして、バッグの新しいインスタンスを作成できます。バッグ内のアイテムは、他に何も保持されていない場合、GCの対象になります。

lock (something)
{
    bag = new ConcurrentBag();
}

またはLukazoidが指摘するように:

var newBag = new ConcurrentBag();
Interlocked.Exchange<ConcurrentBag>(ref bag, newBag);

ただし、コンテンツをビニングする簡単な方法は、アイテムがアクセスを必要とするときはいつでもロックを取得することを前提としていConcurrentBagます。これはコストがかかり、それ自体に組み込まれているパフォーマンスチューニングを無効にする可能性があります。

現時点で他に何もバッグにアクセスできないことがわかっている場合は、それを祈り、ロックしないでください:-)


バッグを消費する場所にバッグのリファレンスのコピーをとるだけの方が良い解決策ではないでしょうbag = newか。そうすれば、免責で行うことができます。
Chris Marisic 2015

1
@ChrisMarisicはい、データの共有をまったく回避できれば、これらの問題は発生しません。しかし、この質問にはあまり文脈がありませんでした。
Adam Houldsworth 2015

10
Interlocked.Exchangeロックよりも優れている可能性があります
Lukazoid 2015年

5
Interlocked.Exchange交換時に別のスレッドがバッグに追加されている場合、どのように機能しますか?それはAdd中にロックされExchangeますか?
ブランドン

2
アシジョンは.NETではアトミックであり、ロックとInterlocked.Exchange冗長性の両方があります(スレッドセーフは提供されません)。
ルー

24

選択した回答は一種の回避策であるため、独自の回避策を追加します。

私の解決策は、System.Collections.Concurrent名前空間で使用可能なすべてのコレクションを調べて、コレクションからすべての要素をクリアするのが簡単なコレクションを見つけることでした。

ConcurrentStackのクラスが持つクリア()コレクションのすべての要素を除去する方法。実際、それは(現在)名前空間で唯一のコレクションです。はい、Push(T element)代わりに行う必要がありますがAdd(T element)、率直に言って、それは時間を節約する価値があります。


1
しかし、彼のコレクションの間には他にも多くの重要な違いがあります。たとえば、特定のアイテムがコレクションに含まれているかどうかを判断する必要がある場合、バッグでは簡単で効率的ですが、スタックではそうではありません。
Servy 2013年

@Servy:ええ、それでも。いいえ、実際、私は賛否両論のリストを書き始めましたが、それは本当にあなたの要件が何であるかに依存します。たとえば、同時コレクションはマルチスレッドアクセスに適していますが、コレクションにインデックスを付けることができないため、コレクションを使用できなくなる可能性があります。質問は特に同時バッグをクリアすることについてであり(それが私がそれに遭遇した理由です)、スレッドセーフを備えたコレクションの簡単なクリアが私の要件でした。私の答えは、コレクションを切り替えることでした。

2
バッグの代わりに並行スタックも使用しています。スタックにクリアがあり、バッグがないのは不思議です。バッグの主な目的は、値を保存し、存在を確認し、すべてまたは単一を削除することです。したがって、並行スタックは「少し制限された実際の並行バッグ」に似たものになります。
マキシム

@Servy特定のアイテムがConcurrentBag?に含まれているかどうかを効率的に判断するにはどうすればよいですか?それを行うためのネイティブプロパティやメソッドが表示されません。Containsカウントされません。これはジェネリックIEnumerableの拡張メソッドであり、効率的ではありません。
TheodorZoulias20年

9

回避策の精神で..ConcurrentDictionary<T, bool>にはアトミッククリアがありますが、キーが存在するかどうかをすばやく確認することもできます。「すばやく」はもちろん相対的な用語ですが、使用法によっては、大きなスタックを列挙するよりも高速な場合があります。


良いですね!これは、そのようなインスタンス用に選択されたコンテナタイプと見なす必要があります。同様にConcurrentStack。
レイテンシー


-2
int cnt = _queue.Count;
for (; cnt > 0; cnt--)
{
     _queue.TryDequeue(out img);
}

無限ループに陥ることはなく、現在の内容をクリアします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.