Як очистити ConcurrentBag
? він не має жодного методу, як Clear
або RemoveAll
...
Відповіді:
Хоча це може бути не зовсім зрозумілим через потенційні умови перегонів, цього достатньо:
while (!myBag.IsEmpty)
{
myBag.TryTake(out T _);
}
Оновлення 10.03.2017: Як правильно зазначає @Lou, призначення є атомним. У цьому випадку створення ConcurrentBag
волі не буде атомним, але введення цього посилання у змінну буде атомним - тому блокування або Interlocked.Exchange
навколо нього не є строго необхідним.
Деякі подальші читання:
присвоєння посилання є атомним, то чому потрібен Interlocked.Exchange (ref Object, Object)?
Чи безпечне присвоєння посилань?
Ви завжди можете заблокувати доступ до самої сумки та створити її нову копію. Тоді предмети, що знаходяться в мішку, зможуть отримати GC, якщо на них більше нічого не тримається:
lock (something)
{
bag = new ConcurrentBag();
}
Або як зазначає Луказоїд:
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 має метод Clear (), який видаляє всі елементи з колекції. Насправді це єдина колекція у просторі імен (на даний момент), яка це робить. Так, вам доведеться Push(T element)
замість цього Add(T element)
, але, чесно кажучи, це коштує витраченого часу.
ConcurrentBag
? Я не бачу жодної власної властивості чи методу для цього. Contains
Не злічити. Це метод розширення для загальних IEnumerable
s, і він є чим завгодно, але не ефективним.
У дусі обхідних шляхів .. ConcurrentDictionary<T, bool>
має атомний Clear, але також дозволяє швидко перевірити, чи існує ключ. "Швидко" - це відносний термін, звичайно, але залежно від вашого використання це може бути швидше, ніж перерахування великого стека.
Починаючи з .NET Core 2.0 / .NET Standard 2.1 / .NET Framework 5.0, існує Clear()
метод на ConcurrentBag<T>
. Див .: ConcurrentBag.Clear .