tpl threading parallel net library for example .net parallel-extensions

.net - threading - parallel list c#



¿Cuál es el propósito de BlockingCollection(Of T) (4)

Alternativamente, AsyncEx proporciona AsyncCollection, que es una versión asíncrona de BlockingCollection. Consulte https://github.com/StephenCleary/AsyncEx/wiki/AsyncCollection

Estoy tratando de entender el propósito de BlockingCollection en el contexto de las nuevas pilas paralelas en .NET 4.

La documentación de MSDN dice:

BlockingCollection se utiliza como un contenedor para una instancia de IProducerConsumerCollection, permitiendo que los intentos de eliminación de la colección se bloqueen hasta que los datos estén disponibles para ser eliminados. De manera similar, se puede crear un BlockingCollection para imponer un límite superior en la cantidad de elementos de datos permitidos en el IProducerConsumerCollection; los intentos de adición a la colección pueden bloquearse hasta que haya espacio disponible para almacenar los elementos agregados.

Sin embargo, cuando observo la implementación de algunos IProducerConsumerCollection, como ConcurrentQueue, veo que proporcionan implementaciones sin bloqueo y sin hilos. Entonces, ¿por qué es necesario el mecanismo de bloqueo que proporciona BlockingCollection? Todos los ejemplos en MSDN muestran cómo se usan esas colecciones a través del envoltorio BlockingCollection, ¿cuáles son los problemas de usar esas colecciones directamente? ¿Qué beneficio produce el uso de BlockingCollection?


Bloquear hasta que se pueda realizar la operación es una conveniencia si no tiene nada más que hacer (o más bien: no puede continuar hasta que se haya realizado la operación).

Si tiene una cola no bloqueante desde la que desea leer datos y no hay datos en este momento, debe sondearlos periódicamente o esperar en algún semáforo, hasta que haya datos. Si la cola se bloquea, eso ya se hace automáticamente.

De manera similar, si intenta agregar a una cola de no bloqueo que está llena, la operación solo fallará y luego tendrá que averiguar qué hacer. La cola de bloqueo solo esperará hasta que haya espacio.

Si tiene algo inteligente que hacer en lugar de esperar (como revisar otra cola en busca de datos, o generar una excepción QueueTooFullException), entonces desea la cola de no bloqueo, pero a menudo no es así.

A menudo, hay una forma de especificar un tiempo de espera en las colas de bloqueo.


El propósito del bloqueo es el bloqueo en sí. Puede hacer que se lean varios subprocesos de la colección y, si no hay datos disponibles, el subproceso permanecerá bloqueado hasta que lleguen nuevos datos.

Además, con la capacidad de establecer un límite de tamaño, puede permitir que el subproceso del productor que está llenando la colección simplemente alimente todo lo que pueda. Cuando la colección alcanza el límite, el hilo solo se bloqueará hasta que los hilos del consumidor hayan hecho espacio para los datos.

De esta manera, puede utilizar la colección para acelerar el rendimiento de los datos, sin hacer ninguna comprobación por sí mismo. Sus hilos solo leen y escriben todo lo que pueden, y la colección se encarga de mantener los hilos funcionando o durmiendo según sea necesario.


Es una de esas cosas que es mucho más fácil de entender una vez que lo haces.

Para consumidor consumidor, tengamos dos objetos, Productor y Consumidor. Ambos comparten una cola que se les da cuando se construyen, para que puedan escribir entre ellos.

Agregar un consumidor productor es bastante familiar, solo con el Completar Adición un poco diferente:

public class Producer{ private BlockingCollection<string> _queue; public Producer(BlockingCollection<string> queue){_queue = queue;} //a method to do something public MakeStuff() { for(var i=0;i<Int.MaxValue;i++) { _queue.Add("a string!"); } _queue.CompleteAdding(); } }

El consumidor no parece tener sentido, hasta que te das cuenta de que el foreach no se detendrá hasta que la cola haya terminado de agregarse. Hasta entonces, si no hay artículos, simplemente volverá a dormir. Y dado que es la misma instancia de la colección en el productor y en el consumidor, puede hacer que el consumidor SOLAMENTE realice ciclos cuando haya cosas que hacer, y no tenga que preocuparse por detenerla, reiniciarla, etc.

public class Consumer() { private BlockingCollection<string> _queue; public Consumer(BlockingCollection<string> queue) { _queue = queue; } public void WriteStuffToFile() { //we''ll hold until our queue is done. If we get stuff in the queue, we''ll start processing it then foreach(var s in _queue.GetConsumingEnumerable()) { WriteToFile(s); } } }

Así que los conectas usando la colección.

var queue = new BlockingCollection<string>(); var producer = new Producer(queue); var consumer = new Consumer(queue); producer.MakeStuff(); consumer.WriteStuffToFile();