thread safe concurrent collection c# concurrency concurrent-collections

concurrent - c# thread safe dictionary



ConcurrentBag-Agregar varios artículos? (4)

Sí :)

Concat es quizás una de las extensiones Enumerable . No agrega nada al ConcurrentBag , solo devuelve un objeto original que contiene el bolso original y todo lo que haya intentado agregar allí.

Tenga en cuenta que el resultado de Concat ya no es un ConcurrentBag , por lo que no querrá usarlo. Es parte del marco LINQ general, lo que hace posible combinar secuencias inmutables. Este marco, por supuesto, no intenta extender las propiedades concurrentes de los operandos al resultado, por lo que el objeto resultante no será tan adecuado para el acceso multiproceso.

(Básicamente, Concat aplica a ConcurrentBag porque expone la IEnumerable<T> ).

¿Hay alguna manera de agregar varios elementos a ConcurrentBag todos a la vez, en lugar de uno a la vez? No veo un método AddRange () en ConcurrentBag, pero hay un Concat (). Sin embargo, eso no funciona para mí:

ConcurrentBag<T> objectList = new ConcurrentBag<T>(); timeChunks.ForEach(timeChunk => { List<T> newList = Foo.SomeMethod<T>(x => x.SomeReadTime > timeChunk.StartTime); objectList.Concat<T>(newList); });

Este código solía estar en un Parallel.ForEach (), pero lo cambié al anterior para poder solucionarlo. La variable newList tiene objetos, pero después de la línea objectList.Concat <>, objectList siempre tiene 0 objetos en ella. ¿Concat <> no funciona de esa manera? ¿Debo agregar elementos a ConcurrentBag uno por uno, con el método Add ()?


Concat es un método de extensión provisto por LINQ. Es una operación inmutable que devuelve otro IEnumerable que puede enumerar la colección de origen seguida inmediatamente por la colección especificada. De ninguna manera, cambia la colección de origen.

Tendrá que agregar sus artículos al ConcurrentBag uno a la vez.


Me enfrenté a un problema similar, tratando de procesar trozos de datos más pequeños en paralelo, porque una gran parte estaba agotando el tiempo de uso del servicio web que estaba usando para acceder a mis datos en el lado de envío, pero no quería que las cosas funcionaran más lentamente procesando cada fragmento en serie. Procesar el registro de datos por registro fue aún más lento: dado que el servicio al que estaba llamando podía manejar solicitudes masivas, sería mejor enviar tantas como fuera posible sin agotar el tiempo.

Como dijo Vlad, concaturar una bolsa concurrente en una lista de un tipo de objeto no devuelve una bolsa concurrente, ¡así que concat no funcionará! (Me llevó un tiempo darme cuenta de que no podía hacer eso).

Pruebe esto en su lugar: cree una List<T> , y luego cree una ConcurrentBag<List<T>> . En cada iteración paralela, se agregará una nueva lista a la bolsa concurrente. Cuando finaliza el bucle paralelo, recorra el ConcurrentBag y concat (o unión si desea eliminar posibles duplicados) a la primera List<T> que creó para "aplanar" todo en una lista.


(Sé que esta es una publicación anterior, pensé en agregar algo).

Al igual que otros han dicho: sí, debe agregarlos uno por uno. En mi caso, agregué un pequeño método de extensión para hacer las cosas un poco más limpias, pero bajo el capó hace lo mismo:

public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd) { foreach (var element in toAdd) { @this.Add(element); } }

Y entonces:

ConcurrentBag<int> ccBag = new ConcurrentBag<int>(); var listOfThings = new List<int>() { 1, 2, 4, 5, 6, 7, 8, 9 }; ccBag.AddRange(listOfThings);

También busqué usar AsParallel para agregar dentro del método de extensión, pero después de ejecutar algunas pruebas al agregar una lista de cadenas de varios tamaños, fue mucho más lento usar AsParallel (como se muestra aquí) en comparación con el ciclo for tradicional.

public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd) { toAdd.AsParallel().ForAll(t => @this.Add(t)); }