2012-04-11 6 views
7

necesito de un solo productor, de un solo consumidor consulta FIFO porque¿Es bueno usar BlockingCollection <T> como consulta FIFO de un solo productor y consumidor único?

  • necesito para procesar los mensajes en el orden que recibieron.
  • Necesito hacer esto asincrónico porque la persona que llama no debe esperar mientras estoy procesando el mensaje.
  • El procesamiento del siguiente mensaje debe iniciarse solo cuando finaliza el procesamiento del mensaje anterior. En ocasiones, la frecuencia de los mensajes de "recepción" es más alta que la frecuencia de los mensajes de "procesamiento". Pero en promedio debería poder procesar todos los mensajes, solo a veces tengo que "poner en cola" un paquete de ellos.

así que es bastante como TCP/IP pienso, donde se tiene un productor y un consumidor, a veces se puede recibir mensajes más rápido que puede procesar, así que hay que consultarlos. Donde el orden ES importante y el que llama no está interesado en absoluto en lo que haces con esas cosas.

Esto suena bastante fácil y es probable que puedo utilizar en general Queue para eso, pero quiero utilizar BlockingCollection por eso, porque no quiero que escribir ningún código con ManualResetEvent etc.

¿Qué tan adecuados para mi tarea BlockingCollection y probablemente puedas sugerir algo más?

Respuesta

11

BlockingCollection clase implementa IProducerConsumerCollection interfaz por lo que se adapta perfectamente a sus necesidades.

Puede crear dos tareas, una para el productor asincrónico y otra como trabajador de consumo. El anterior agregaría artículos al BlockingCollection y el último solo consumiría tan pronto como los nuevos estén disponibles en orden FIFO.

aplicación productor-consumidor muestra usando TPL Tasks y BlockingCollection:

class ProducerConsumer 
{ 
    private static BlockingCollection<string> queue = new BlockingCollection<string>(); 

    static void Main(string[] args) 
    { 
     Start(); 
    } 

    public static void Start() 
    { 
     var producerWorker = Task.Factory.StartNew(() => RunProducer()); 
     var consumerWorker = Task.Factory.StartNew(() => RunConsumer()); 

     Task.WaitAll(producerWorker, consumerWorker); 
    } 

    private static void RunProducer() 
    { 
     int itemsCount = 100; 

     while (itemsCount-- > 0) 
     { 
      queue.Add(itemsCount + " - " + Guid.NewGuid().ToString()); 
      Thread.Sleep(250); 
     } 
    } 

    private static void RunConsumer() 
    { 
     foreach (var item in queue.GetConsumingEnumerable()) 
     { 
      Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.ffff") + " | " + item); 
     } 
    } 
} 

IProducerConsumerCollection:

define métodos para manipular colecciones de hilo de seguridad destinados a productor/uso de los consumidores. Esta interfaz proporciona una representación unificada para colecciones de productores/consumidores, de forma que las abstracciones de mayor nivel como System.Collections.Concurrent.BlockingCollection (Of T) pueden usar la colección como mecanismo de almacenamiento subyacente.

+0

Espero que la implementación FIFO predeterminada de 'BlockingCollection' no se modifique en algunas de las siguientes versiones , pero esta es otra pregunta ... – javapowered

+0

Creo que deberías estar bien siempre y cuando estés haciendo referencia a la interfaz 'IProducerConsumerCollection', y la implementación de las clases BCL no puede cambiar de manera principal como FIFO a otra cosa – sll

+2

Veo que el método Start() espera a los dos tareas para completar. Obviamente, la tarea 'producerWorker' terminará, pero el' consumerWorker' nunca terminará. ¿Debería tomarse esto en cuenta? –

0

Dado que es una cola que necesita, ¿por qué no se pega a una cola? Puede usar un Syncrhonized Queue.

+0

No bloquea. –

+0

Martin right, [MSDN] (http://msdn.microsoft.com/en-us/library/system.collections.queue.synchronized.aspx): 'Enumerar a través de una colección no es intrínsecamente un procedimiento seguro para subprocesos. Incluso cuando una colección está sincronizada, otros subprocesos aún pueden modificar la colección, lo que hace que el enumerador genere una excepción. Para garantizar la seguridad del subproceso durante la enumeración, puede bloquear la recopilación durante toda la enumeración o atrapar las excepciones resultantes de los cambios realizados por otro subproceso' – sll

Cuestiones relacionadas