FIFO队列导致IIS处理器达到100%的最大值

本文关键字:100% 最大值 处理器 队列 IIS FIFO | 更新日期: 2023-09-27 17:51:11

我在IIS上有一个单例服务类,作为web应用程序的一部分(出于数据缓存的原因,该服务是单例的)。向服务发出请求的浏览器客户端可以得到以下三种结果之一:

1)缓存中有数据并且数据没有过期(过期)-我们返回该数据。非常快。2)缓存的数据已经过期,但是另一个请求已经在查询数据库。我们返回缓存的数据。3)缓存的数据过期,没有请求对DB进行查询。该请求向前移动以进行查询。

但是,针对同名存储过程的数据库查询必须排队(需求)。

因此,我编写了这个queue类,它被设计成将这些查询排队并连续运行,而不是并发运行。这些队列类是根据需要创建的,并存储在单例类的列表中。当请求移动到第(3)部分时,它会找到与其存储过程名称匹配的队列类,并将请求提交给队列类。然后,它等待数据从DB返回,以便为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;
  }
}

FIFO队列导致IIS处理器达到100%的最大值

我不知道我是否理解问题但是你可以很简单地重写

private object _lockObj=new object();
public ReportTable GetReportTable(ReportQuery query)
{
  lock(_lockObj){
    var table = query.GetNewReportTable();
    return table;
  }
}

我是这么做的。

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.Wait(_queue);
    }
    _inUse = true;
    firstQueryInQueue = _queue.Dequeue();
    var table = firstQueryInQueue.GetNewReportTable();
    _inUse = false;
    Monitor.Pulse(_queue);
    return table;
  }
}

之前没有工作的原因是因为我对Monitor.Wait()和Monitor.Pulse()缺乏全面的了解。我在代码中的错误位置使用Pulse()。幸运的是,这里有一个很好的答案,它很好地描述了Wait()和Pulse()。

关键是在集合更改后使用Pulse(),并为后续排队线程提供测试条件的机会,该条件是:我的查询是否在队列中第一个?是否已经有人提出疑问了?如果测试失败,线程调用Wait(),这会将其放入等待队列中,并且不会占用处理器周期。当在前面并且正在执行查询的线程完成时,它将_inUse标志翻转为false并调用Pulse(),唤醒下一个线程之一,以便检查条件。

在执行此解决方案并观察任务管理器一天后,我很高兴地看到服务器上的负载为1%到5%,并且CPU从未像以前那样爬升到100%。

我对此做了很多阅读,似乎PulseAll()在这种情况下可能是更好的调用,但到目前为止Pulse()正在工作,我们还没有遇到任何问题。