2012-01-10 11 views
6

Ho un'applicazione a processo singolo a due thread. Thread 1 ascolterà un feed di dati di mercato e aggiornerà la quotazione più recente su migliaia di azioni. Il thread 2 eseguirà un timer a una frequenza di campionamento e scatta un'istantanea delle quotazioni più recenti per l'elaborazione. In effetti, ho bisogno di eseguire il down-campionamento di un feed di dati di mercato estremamente veloce.Che cos'è un modo veloce, efficiente per la memoria, di passare i dati tra i thread in C#?

La mia prima ipotesi su una soluzione è utilizzare un BlockingQueue. Per fare questo ho bisogno di spostare la funzionalità del timer in Thread 1, cosa che posso fare controllando l'orologio ogni volta che arriva un aggiornamento di quota e inviare un'istantanea delle virgolette sulla coda alla frequenza di campionamento. La mia preoccupazione qui è che la coda consumerà molta memoria e la garbage collection rallenterà le cose.

La mia seconda ipotesi è quella di fare in modo che il Thread 1 copi i dati in un membro bloccato alla frequenza di campionamento, a cui può accedere il Thread 2. La mia preoccupazione qui è che le serrature saranno lente.

Il mio thirt lo indovina per rendere volatile la citazione primitiva. Poiché un solo thread scrive e un solo thread legge, forse questo è appropriato?

Esiste un modo migliore di comunicare i dati tra i thread per questa applicazione sensibile alla latenza? Questa non è un'applicazione ad altissima frequenza. Riesco a tollerare le latenze dell'ordine di decine di ms.

risposta

7

Se avete solo 2 filetti di accesso a questa risorsa (cioè delle letture simultanee non sono necessari), quindi il più semplice (e uno dei più veloci) sarebbe solo quella di utilizzare la parola chiave lock:

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); 
     } 
    } 
} 

Se invece sono richieste letture simultanee, questa sarebbe una buona misura per the ReaderWriterLockSlim class. È possibile acquisire il blocco di lettura durante la copia dei dati e il blocco di scrittura durante la scrittura dei dati ad esempio:

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(); 
    } 
} 

Oppure, se si sta utilizzando .Net 4 o superiore ci sono molte splendide collezioni in concomitanza modificabili in the System.Collections.Concurrent namespace che probabilmente si potrebbe usare senza qualsiasi problema (sono oggetti senza blocco e sono generalmente molto veloci - e some performance enhancements are coming in .Net 4.5 too!).

+0

Avete richiesto il blocco della lettura entrambi i tempi (lettura/scrittura)? :) –

+0

@AmarPalsapure Grazie, errore di battitura fisso! –

+0

Thx per la tua risposta. Proverò le serrature per iniziare. Cosa ne pensi dell'uso volatile? –

0

Non è un caso di coda Producer-Consumer? Il consumatore attenderà (Monitor.Wait) quando il nuovo produttore inizierà a pulsare quando entrerà il nuovo feed. Appena entreranno i nuovi/aggiornati feed, Producer popolerà la coda e attiverà Monitor.Pulse.

Problemi correlati