什么是在C#中的线程之间传递数据的快速,内存高效的方法? [英] What is a fast, memory efficient way to pass data between threads in C#?

查看:225
本文介绍了什么是在C#中的线程之间传递数据的快速,内存高效的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个单进程,两线程的应用程序。线程1将侦听市场数据提要并更新数千种股票的最新报价。线程2将以采样频率运行一个计时器,并为处理最新的报价拍摄快照。实际上,我需要对非常快速的市场数据提要进行下采样。<​​/ p>

我对解决方案的第一个猜测是使用BlockingQueue。为此,我需要将计时器功能移到线程1中,我可以通过在每次引用更新到来时检查时钟,并以采样频率将引用的快照发送到队列中来完成。我在这里担心的是队列将消耗大量内存,而垃圾回收将使事情变慢。



我的第二个猜测是让线程1将数据复制到锁定状态线程2可以访问的采样频率成员。我在这里担心的是锁会很慢。



我很想,它会使报价原语变得不稳定。既然只写一个线程,只读一个线程,这是否合适?



对于这种对延迟敏感的应用程序,是否有最佳实践在线程之间传递数据?这不是超高频应用。我可以容忍数十毫秒的延迟。

解决方案

如果只有2个线程访问此资源(即,并发读取)不需要),那么最简单(也是最快的方法之一)就是使用 lock 关键字:

 公共类QuoteStore 
{
private readonly List< Quote> _quotes = new List< Quote>();
私有只读对象_mutex = new object();

公共ReadOnlyCollection< Quote> GetQuotes()
{
锁(_mutex)
{
return _quotes.ToReadOnly();
}
}

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

如果需要并发读取这对于 ReaderWriterLockSlim类是一个很好的选择。您可以在复制数据时获得读取锁定,而在写入数据时获得写入锁定,例如:

 公共类QuoteStore:IDisposable 
{
私有只读ReaderWriterLockSlim _mutex = new ReaderWriterLockSlim();
私有只读List< Quote> _quotes = new List< Quote>();

公共ReadOnlyCollection< Quote> GetQuotes()
{
_mutex.EnterReadLock();
试试
{
return _quotes.ToReadOnly();
}
最后
{
_mutex.ExitReadLock();
}
}

public void AddQuote()
{
_mutex.EnterWriteLock();
试试
{
_quotes.Add(quote);
}
最终
{
_mutex.ExitWriteLock();
}
}

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

或者如果您使用.Net 4或更高版本 System.Collections.Concurrent命名空间中有许多精彩的可同时修改的集合您可能可以毫无问题地使用它们(它们是无锁对象,通常非常快-和。Net 4.5也将提供一些性能增强功能!)。


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.

解决方案

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!).

这篇关于什么是在C#中的线程之间传递数据的快速,内存高效的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆