クリアする方法はConcurrentBag
?Clear
またはのような方法はありませんRemoveAll
...
回答:
競合状態の可能性があるため、完全にはクリアされない場合がありますが、これで十分です。
while (!myBag.IsEmpty)
{
myBag.TryTake(out T _);
}
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
か。そうすれば、免責で行うことができます。
Interlocked.Exchange
ロックよりも優れている可能性があります
Interlocked.Exchange
交換時に別のスレッドがバッグに追加されている場合、どのように機能しますか?それはAdd
中にロックされExchange
ますか?
Interlocked.Exchange
冗長性の両方があります(スレッドセーフは提供されません)。
選択した回答は一種の回避策であるため、独自の回避策を追加します。
私の解決策は、System.Collections.Concurrent名前空間で使用可能なすべてのコレクションを調べて、コレクションからすべての要素をクリアするのが簡単なコレクションを見つけることでした。
ConcurrentStackのクラスが持つクリア()コレクションのすべての要素を除去する方法。実際、それは(現在)名前空間で唯一のコレクションです。はい、Push(T element)
代わりに行う必要がありますがAdd(T element)
、率直に言って、それは時間を節約する価値があります。
ConcurrentBag
?に含まれているかどうかを効率的に判断するにはどうすればよいですか?それを行うためのネイティブプロパティやメソッドが表示されません。Contains
カウントされません。これはジェネリックIEnumerable
の拡張メソッドであり、効率的ではありません。
回避策の精神で..ConcurrentDictionary<T, bool>
にはアトミッククリアがありますが、キーが存在するかどうかをすばやく確認することもできます。「すばやく」はもちろん相対的な用語ですが、使用法によっては、大きなスタックを列挙するよりも高速な場合があります。
.NET Core 2.0 / .NET Standard 2.1 / .NET Framework 5.0の時点で、にClear()
メソッドがありConcurrentBag<T>
ます。参照:ConcurrentBag.Clear。