¿Cómo borrar el ConcurrentBag
? no tiene ningún método como Clear
o RemoveAll
...
Respuestas:
Aunque puede que no esté completamente claro debido a una posible condición de carrera, esto es suficiente:
while (!myBag.IsEmpty)
{
myBag.TryTake(out T _);
}
Actualización 10/03/2017: Como @Lou señala correctamente, la asignación es atómica. En este caso, la creación de ConcurrentBag
no será atómica, pero poner esa referencia en la variable será atómica, por Interlocked.Exchange
lo que no es estrictamente necesario bloquearla o rodearla.
Algunas lecturas adicionales:
¿Es una tarea de referencia segura para subprocesos?
Siempre puede bloquear el acceso a la bolsa y crear una nueva instancia de la misma. Los artículos en la bolsa serán elegibles para GC si nada más los está reteniendo:
lock (something)
{
bag = new ConcurrentBag();
}
O como señala Lukazoid:
var newBag = new ConcurrentBag();
Interlocked.Exchange<ConcurrentBag>(ref bag, newBag);
Sin embargo, una manera fácil de agrupar el contenido, asume que siempre que un elemento desea acceder, también obtiene el bloqueo; esto podría ser costoso y podría anular el ajuste de rendimiento que se ha realizado en ConcurrentBag
sí mismo.
Si sabe que nada más accederá a la bolsa en este momento, alójela y reza y no la cierre :-)
bag = new
con impunidad?
Interlocked.Exchange
puede ser mejor que un candado
Interlocked.Exchange
funciona si se agrega otro hilo a la bolsa en el momento del intercambio? ¿ Add
Eso se bloquea durante el Exchange
?
Interlocked.Exchange
son redundantes aquí (y no proporcionan seguridad para subprocesos).
La respuesta seleccionada es una especie de, bueno, una solución alternativa, así que estoy agregando mi propia solución.
Mi solución fue mirar todas las colecciones disponibles en el espacio de nombres System.Collections.Concurrent para encontrar una en la que fuera trivial borrar todos los elementos de la colección.
La clase ConcurrentStack tiene un método Clear () que elimina todos los elementos de la colección. De hecho, es la única colección en el espacio de nombres (actualmente) que lo hace. Sí, tiene que Push(T element)
hacerlo en lugar de hacerlo Add(T element)
, pero, francamente, vale la pena el tiempo ahorrado.
ConcurrentBag
? No veo ninguna propiedad o método nativo para hacer eso. El Contains
no cuenta. Es un método de extensión para IEnumerable
s genéricos , y es todo menos eficiente.
En el espíritu de las soluciones ... ConcurrentDictionary<T, bool>
tiene un Clear atómico, pero también le permite comprobar rápidamente si existe una clave. 'Rápido' es un término relativo, por supuesto, pero dependiendo de su uso, puede ser más rápido que enumerar una pila grande.
A partir de .NET Core 2.0 / .NET Standard 2.1 / .NET Framework 5.0, hay un Clear()
método en ConcurrentBag<T>
. Consulte: ConcurrentBag.Clear .