What is a fast, memory efficient way to pass data

2020-07-10 20:16发布

I have a one-process, two-thread application. Thread 1 will listen to a market data feed and update the most recent quote on thousands of stocks. Thread 2 will run a timer at a Sampling Frequency and take a snapshot of the most recent quotes for processing. Effectively, I need to down-sample an extremely fast market data feed.

My first guess at a solution is to use a BlockingQueue. To do this I need to move the timer functionality into Thread 1, which I can do by checking the clock every time a quote update comes in and send a snapshot of the quotes onto the queue at the Sampling Frequency. My concern here is that the queue will consume a lot of memory and garbage collection will slow things down.

My second guess is to have Thread 1 copy the data into a locked member at the Sampling Frequency, which Thread 2 can access. My concern here is that the locks will be slow.

My thirt guess it to make the quote primitives volatile. Since one thread only writes and one thread only reads, maybe this is appropriate?

Is there a best practice way to communicate the data between the threads for this latency sensitive application? This is not an ultra-high frequency application. I can tolerate latencies on the order of tens of ms.

2条回答
小情绪 Triste *
2楼-- · 2020-07-10 20:26

Isn't it a case of Producer-Consumer Queue? Consumer will wait(Monitor.Wait) upon the Producer to pulse when new feed comes in. As soon as the new/updated feeds comes in, Producer will populate the Queue and fire Monitor.Pulse.

查看更多
太酷不给撩
3楼-- · 2020-07-10 20:34

If you only have 2 threads accessing this resource (ie concurrent reads are not required), then the simplest (and one of the quickest) would just be to use the lock keyword:

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

If however concurrent reads are required this would be a good fit for the ReaderWriterLockSlim class. You can acquire the read lock when copying data and the write lock when writing data eg:

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

Or if you are using .Net 4 or above there are many wonderful concurrently modifiable collections in the System.Collections.Concurrent namespace which you could probably use without any problem (they are lock free objects and are generally very quick - and some performance enhancements are coming in .Net 4.5 too!).

查看更多
登录 后发表回答