Як очистити 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Не злічити. Це метод розширення для загальних IEnumerables, і він є чим завгодно, але не ефективним.
У дусі обхідних шляхів .. ConcurrentDictionary<T, bool>має атомний Clear, але також дозволяє швидко перевірити, чи існує ключ. "Швидко" - це відносний термін, звичайно, але залежно від вашого використання це може бути швидше, ніж перерахування великого стека.
Починаючи з .NET Core 2.0 / .NET Standard 2.1 / .NET Framework 5.0, існує Clear()метод на ConcurrentBag<T>. Див .: ConcurrentBag.Clear .