2012-01-10 17 views
6

Tengo una aplicación de un solo proceso y dos hilos. El Tema 1 escuchará un feed de datos de mercado y actualizará la cotización más reciente de miles de acciones. El Subproceso 2 ejecutará un temporizador a una Frecuencia de muestreo y tomará una instantánea de las cotizaciones más recientes para el procesamiento. De hecho, necesito bajar la muestra de un feed de datos de mercado extremadamente rápido.¿Cuál es una forma rápida y eficiente de memoria para pasar datos entre hilos en C#?

Mi primera conjetura sobre una solución es usar un BlockingQueue. Para hacer esto, necesito mover la funcionalidad del temporizador al Hilo 1, lo cual puedo hacer comprobando el reloj cada vez que aparece una actualización de cotizaciones y enviar una instantánea de las cotizaciones a la cola en la Frecuencia de muestreo. Mi preocupación aquí es que la cola consumirá mucha memoria y la recolección de basura disminuirá la velocidad.

Mi segunda suposición es hacer que el subproceso 1 copie los datos en un miembro bloqueado en la frecuencia de muestreo, a la que puede acceder el subproceso 2. Mi preocupación aquí es que los bloqueos serán lentos.

Creo que es necesario hacer que las primitivas de la cita sean volátiles. Dado que un hilo solo se escribe y un hilo solo se lee, ¿puede ser apropiado?

¿Existe una forma de mejores prácticas para comunicar los datos entre los subprocesos para esta aplicación sensible a la latencia? Esta no es una aplicación de frecuencia ultra alta. Puedo tolerar latencias del orden de decenas de ms.

Respuesta

7

Si sólo tiene 2 hilos para acceder a este recurso (es decir, lecturas simultáneas no son necesarios), entonces el más simple (y uno de los más rápidos) sólo sería utilizar el lock palabra clave:

public class QuoteStore 
{ 
    private readonly List<Quote> _quotes = new List<Quote>(); 
    private readonly object _mutex = new object(); 

    public ReadOnlyCollection<Quote> GetQuotes() 
    { 
     lock (_mutex) 
     { 
     return _quotes.ToReadOnly(); 
     } 
    } 

    public void AddQuote() 
    { 
     lock (_mutex) 
     { 
     _quotes.Add(quote); 
     } 
    } 
} 

Sin embargo, si se requieren lecturas simultáneas, esto sería una buena opción para the ReaderWriterLockSlim class. Puede adquirir el bloqueo de lectura al copiar datos y el bloqueo de escritura al escribir datos, por ejemplo:

public class QuoteStore : IDisposable 
{ 
    private readonly ReaderWriterLockSlim _mutex = new ReaderWriterLockSlim(); 
    private readonly List<Quote> _quotes = new List<Quote>(); 

    public ReadOnlyCollection<Quote> GetQuotes() 
    { 
     _mutex.EnterReadLock(); 
     try 
     { 
     return _quotes.ToReadOnly(); 
     } 
     finally 
     { 
     _mutex.ExitReadLock(); 
     } 
    } 

    public void AddQuote() 
    { 
     _mutex.EnterWriteLock(); 
     try 
     { 
     _quotes.Add(quote); 
     } 
     finally 
     { 
     _mutex.ExitWriteLock(); 
     } 
    } 

    public void Dispose() 
    { 
     _mutex.Dispose(); 
    } 
} 

O si está utilizando .Net 4 o superior hay muchas maravillosas colecciones simultáneamente modificables en the System.Collections.Concurrent namespace que probablemente podría utilizar sin cualquier problema (son objetos sin traba y generalmente son muy rápidos, ¡y some performance enhancements are coming in .Net 4.5 too!).

+0

¿Necesitaba bloqueo de lectura en ambos momentos (lectura/escritura)? :) –

+0

@AmarPalsapure ¡Gracias, error de escritura! –

+0

Thx por su respuesta. Probaré los candados para comenzar. ¿Qué piensas sobre el uso de volátiles? –

0

¿No es un caso de Producer-Consumer Queue? El consumidor esperará (Monitor.Wait) en el productor para que emita un pulso cuando ingrese un nuevo feed. Tan pronto como ingresen los feeds nuevos/actualizados, el productor rellenará la cola y disparará el monitor.Pulse.

Cuestiones relacionadas