ConcurrentBag
をクリアするには? Clear
やRemoveAll
...などのメソッドはありません。
T someItem;
while (!myBag.IsEmpty)
{
myBag.TryTake(out someItem);
}
2017年10月3日更新:@Louが正しく指摘しているように、割り当てはアトミックです。この場合、ConcurrentBag
の作成はアトミックではありませんが、その参照を変数に入れますwillアトミック-したがってロックまたはInterlocked.Exchange
周りは厳密には必要ありません。
さらにいくつかの読書:
参照の割り当てはアトミックであるため、なぜInterlocked.Exchange(ref Object、Object)が必要ですか?
バッグ自体へのアクセスを常にロックして、その新しいインスタンスを作成できます。バッグ内のアイテムは、他に何も保持されていない場合、GCの対象となります。
lock (something)
{
bag = new ConcurrentBag();
}
または、ルカゾイドが指摘するように:
var newBag = new ConcurrentBag();
Interlocked.Exchange<ConcurrentBag>(ref bag, newBag);
ただし、コンテンツを簡単にビンに入れる方法は、アイテムがアクセスを必要とするときはいつでもロックを取得することを前提としています。これは高価であり、ConcurrentBag
自体のパフォーマンスチューニングを無効にする可能性があります。
この時点で他の人がバッグにアクセスしないことを知っている場合は、それを手で祈り、ロックしないでください:-)
選択した答えは一種の回避策であるため、独自の回避策を追加しています。
私の解決策は、 System.Collections.Concurrent 名前空間で使用可能なすべてのコレクションを調べて、コレクションからすべての要素をクリアするのが簡単だったコレクションを見つけることでした。
ConcurrentStack クラスには、コレクションからすべての要素を削除する Clear() メソッドがあります。実際、それは名前空間内の(現在)唯一のコレクションです。はい、Push(T element)
の代わりにAdd(T element)
を使用する必要がありますが、率直に言って時間を節約する価値があります。
ループでオブジェクトを1つずつ削除できます。
object result;
while (bag.TryTake(out result));
ループが終了した後、別のスレッドによる次のステートメントの前にアイテムを追加できるため、このループの後にバッグが空であることは保証されないことに注意してください。
回避策の精神で.. ConcurrentDictionary<T, bool>
にはアトミッククリアがありますが、キーが存在するかどうかをすばやく確認することもできます。 「クイック」はもちろん相対的な用語ですが、使用状況によっては、大きなスタックを列挙するよりも速い場合があります。