Как очистить ConcurrentBag
? у него нет такого метода, как Clear
или RemoveAll
...
Ответы:
Хотя это может быть не полностью очищено из-за потенциального состояния гонки, этого достаточно:
while (!myBag.IsEmpty)
{
myBag.TryTake(out T _);
}
Обновление 10/03/2017: как правильно указывает @Lou, назначение является атомарным. В этом случае создание объекта ConcurrentBag
не будет атомарным, но помещение этой ссылки в переменную будет атомарным, поэтому блокировка или блокировка Interlocked.Exchange
не требуется.
Дальнейшее чтение:
присвоение ссылки является атомарным, так зачем нужен Interlocked.Exchange (ref Object, Object)?
Является ли задание ссылки потокобезопасным?
Вы всегда можете заблокировать доступ к самой сумке и создать ее новый экземпляр. После этого предметы в сумке будут доступны для сборки мусора, если за них больше ничего не держится:
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 .