许多作家最有效的锁定单读者并发模型?

问题描述:

所以我有很多线程正在为我提供输入数据,这些数据必须按照到达顺序由单个线程处理。目前,所有输入项都被插入到一个队列中,并且对队列的读/写操作受到C#锁定语句的保护。但是,随着时间的推移,应用程序的CPU使用率会上升到不可接受的程度,并且分析器说大部分CPU时间都花在锁定语句本身上。是否有更有效的同步方法取代锁定,支持许多编写者和一个阅读器?许多作家最有效的锁定单读者并发模型?

听起来好像作家们正在争夺对方的锁。考虑一个模型,其中每个作者都有自己的队列,读者使用Peek method来读取每个队列中的第一条消息而不删除它。然后读者可以在队列之间继续迭代,从每个队列的第一组项目中窥视第一项,然后删除并处理第一项。它会比当前的架构慢,但应该消除作者之间的锁争用。

一个简单的例子可能看起来像:

public class TimestampedItem<T> : IComparable<TimestampedItem<T>> 
{ 
    public DateTime TimeStamp { get; set; } 
    public T Data { get; set; } 
    public int CompareTo(TimestampedItem<T> other) 
    { 
     return TimeStamp.CompareTo(other.TimeStamp); 
    } 
} 

public void ReadFirstFromEachQueue<T>(IEnumerable<Queue<TimestampedItem<T>>> queues) 
{ 
    while (true) 
    { 
     var firstItems = new List<TimestampedItem<T>>(queues.Select(q => { lock (q) { return q.Peek(); } })); 
      ProcessItem(firstItems.OrderBy(tsi => tsi.TimeStamp).First()); 
     } 
    } 
} 

这可能是一个很大的变化,以您的应用程序,但你可以考虑让你的队列外部应用程序(例如MSMQ),然后你可以有你的作家线程写入该队列的内容。准备就绪后,您的读者可以随时关闭这些项目。如果你的cpu时间的大部分时间正好在你的队列的锁上(我假设你实际上并没有锁定正在放入队列的项目的工作),那么将队列外延放到你的应用程序可以真正帮助。理想情况下,您还可以将写作和阅读分解为独立的流程。

要检查的另一件事是,您锁定的对象未被用于锁定应用程序中的其他位置。监视器(锁语句背后的东西)可能是最轻的线程同步方法,所以最好重新构建一些东西以避免锁定在执行项目处理的同一个进程中。

如果您使用的是.NET版本4.0然后你可以使用ConcurrentQueue这是ConcurrentCollections的一部分,而不是正常的Queue,然后读/你的数据写入队列时摆脱了锁,在ConcurrentCollections是设计用于如果不使用4.0你可以处理并发读/锁免费代码写..

是只锁住,如果没有其他的锁是高跟,可以实现通过使用Monitor.TryEnter代替locklock本身是Monitor.EnterMonitor.Exit的组合..,样本实施将是:

private readonly object _syncObject = new object(); 

private bool TryUpdate(object someData) 
{ 
    if (Monitor.TryEnter(_syncObject)) 
    { 
     try 
     { 
      //Update the data here. 

      return true; 
     } 
     finally 
     { 
      Monitor.Exit(_SyncObject); 
     } 
    } 

    return false; 
} 
+0

Monitor.TryEnter优于Monitor.Enter的优点是什么? – GWLlosa

+0

第一个“Monitor.TryEnter”不会阻塞等待输入,如果使用了'lock',它将返回false而不是等待它在该行处为空。 –