【发布时间】:2013-01-10 15:00:44
【问题描述】:
我在 IIS 上有一个单例服务类作为 Web 应用程序的一部分(出于数据缓存原因,该服务是单例)。向服务发出请求的浏览器客户端可能会产生以下三种结果之一:
1) 缓存中有数据且数据未过期(陈旧) - 我们返回此数据。非常快。 2)缓存的数据过期了,但是另一个请求已经在查询数据库了。我们返回了缓存的数据。 3)缓存数据过期,没有请求对数据库进行查询。该请求向前移动以进行查询。
但是,针对同名存储过程的数据库查询必须排队(要求)。
因此,我编写了这个队列类,旨在将这些查询排队并连续运行它们,而不是同时运行。这些队列类根据需要创建并存储在单例类的列表中。当请求移动到第 (3) 部分时,它会找到与其存储过程名称匹配的队列类,并将请求提交给队列类。然后它一直等到数据从数据库返回,以便它可以为 HTML 请求提供服务。
不幸的是,在使用此代码几个小时后,服务器进程的最大值为 100%。
我不确定改进它的最佳方法是什么,因为多线程编码不是我的专长。
队列类代码如下:
public ReportTable GetReportTable(ReportQuery query)
{
lock (_queue)
{
_queue.Enqueue(query);
Monitor.Pulse(_queue);
}
lock (_queue)
{
var firstQueryInQueue = _queue.Peek();
while (_inUse || firstQueryInQueue == null || firstQueryInQueue.GetHashCode() != query.GetHashCode())
{
Monitor.Pulse(_queue);
Monitor.Wait(_queue);
}
_inUse = true;
firstQueryInQueue = _queue.Dequeue();
var table = firstQueryInQueue.GetNewReportTable();
_inUse = false;
Monitor.Pulse(_queue);
return table;
}
}
【问题讨论】:
-
从 .NET 4.0 开始,框架中已经有一个
ConcurrentQueue为你写了:( MSDN ) 你能用吗? -
我曾一度尝试使用 Nicholas,但它似乎并不真正适合我的情况。排队物品很容易。这是让调用线程等待而不会占用处理器时间的问题。
-
如您所见,编写并发队列很难做到正确。如果可以的话,我建议你尝试使用框架实现。如果您想了解更多关于正确使用
Monitor的信息,我写了一篇您可能喜欢阅读的文章:Wait and Pulse demystified -
@ChrisHolmes - 好的,改用 BlockingCollection。
-
我不认为 BlockingCollection 解决了我的问题 Martin。也许我误解了我读过的文档。但在我的特殊情况下,调用此方法的线程与必须等待和消耗的线程相同。调用此方法的单个线程必须 (1) 将其项入队 (2) 等待其项找到到达队列前面的方式 (3) 将其项出列并开始工作。我需要做的是让每个调用线程等待而不占用处理器时间。我在这里尝试做的是接受并发调用并使它们串行,而不需要猛击处理器。
标签: c# multithreading iis queue fifo