【问题标题】:Problem with IHttpAsyncHandler and ASP.NET "Requests Executing" counterIHttpAsyncHandler 和 ASP.NET“请求执行”计数器的问题
【发布时间】:2011-05-25 11:06:11
【问题描述】:

已解决:

我找到了解决方案。 不知道为什么会这样,但是将应用程序池类型从“集成”切换到“经典”可以解决问题。现在“请求执行”继续上升,实际的应用程序池进程线程仍然很低(约 31 个线程),并且应用程序非常响应(应该如此)。

我使用的是 .Net 2.0,所以可能存在问题 - 尝试用谷歌搜索,但没有成功。

Joe Enzminger's reply for an explanation
再次感谢大家。

ps。该代码用于在线打台球(台球) - Windows(免费)版本here 供任何好奇和勇敢尝试的人使用:)

你好,

我已经实现了客户端应用程序“轮询”以等待服务器通知的 IHttpAsyncHandler。通知是由服务器上的其他“活动”生成的,异步处理程序根本不起作用。

执行步骤为:

IHttpAsyncHandler.BeginProcessRequest

    Create AsyncResult instance and add it to a "registered clients" collection

    return the AsyncResult

...其他服务器活动将生成通知发送给注册客户端...

AsyncResult.CompleteCall called as a result of the generated notification(s).

IHttpAsyncHandler.EndProcessRequest is called

    The notification(s) attached to the AsyncResult are written to the response stream.

问题:

我已经在具有 Windows Server 2008 SP2 和 1 个 cpu 内核的 VM 上的 IIS7 上对此进行了测试。在 12 个客户端注册通知后(在 Async.ashx 上使用 HTTP GET),性能下降到后续客户端无法连接的程度。

当我检查 ASP.NET 性能计数器时,“请求执行”计数器随着每个客户端注册而上升并保持在 12(这似乎是它的最大值 - 可能是每个 CPU 的线程池大小)。

我觉得这很令人困惑。我认为异步处理程序的全部目的是为其他连接释放线程。看来情况并非如此,所以我一定做错了什么!

为什么 ASP.NET 在等待我的 AsyncResult 完成时会占用一个线程?这是配置问题吗?我需要做一些具体的事情来表明这是一个异步处理程序吗?

谢谢你, 尼科斯。

编辑:添加以下代码:

public class AsyncResult : IAsyncResult
{
    private AsyncCallback _cb;
    private object _state;
    private ManualResetEvent _event;
    private bool _completed;
    private bool _completedsynchronously;
    private HttpContext _context;
    private byte[] _data;
    private int _datalength;
    private object _lock = new object();

    public AsyncWaitResult(AsyncCallback cb, object state, HttpContext context)
    {
        _context = context;
        _cb = cb;
        _state = state;
    }

    public void Close()
    {
        if (_event != null)
        {
            _event.Close();
            _event = null;
        }
    }

    public HttpContext Context { get { return _context; } }
    public Object AsyncState { get { return _state; } }
    public bool CompletedSynchronously { get { return _completedsynchronously; } }
    public bool IsCompleted { get { return _completed; } }
    public byte[] Data { get { return _data; } }
    public int DataLength { get { return _datalength; } }

    public WaitHandle AsyncWaitHandle
    {
        get
        {
            lock (_lock)
            {
                if (_event == null)
                    _event = new ManualResetEvent(_completed);
                return _event;
            }
        }
    }

    public void CompleteCall(byte[] data, int length, bool completedsynchronously)
    {
        _data = data;
        _datalength = length;
        _completedsynchronously = completedsynchronously;

        lock (_lock)
        {
            _completed = true;
            if (_event != null)
                _event.Set();
        }

        if (_cb != null)
            _cb(this);
    }
}


public class Outbound : IHttpAsyncHandler
{
    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object state)
    {
            AsyncResult asyncresult = new AsyncResult(cb, state, context);

            RegisteredClients.Instance.Add(asyncresult);

            return asyncresult;
    }

    public void EndProcessRequest(IAsyncResult ar)
    {
        AsyncResult result = (AsyncResult)ar;
        if (result != null)
        {
            result.Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            result.Context.Response.ContentType = "application/octet-stream";
            result.Context.Response.AddHeader("Connection", "keep-alive");

            if (result.Data != null)
                result.Context.Response.OutputStream.Write(result.Data, 0, result.DataLength);

            result.Close();
        }
    }

    public void ProcessRequest(HttpContext context){}

    public bool IsReusable { get { return true; } }
}

【问题讨论】:

  • 我认为您需要发布更详细的代码。由于未能正确实现异步模式,这听起来像是某种“泄漏”,但很难说。
  • 完成了——真的很简单。如果您需要澄清,请告诉我。
  • RegisteredClients.Instance.Add() 不能以任何理由阻止,可以吗?
  • 还有一个问题 - 在您使用的模式中,我只会为 completedsynchronously 属性返回“false”。有没有在调用 CompleteCall() 时将该参数设置为 true 的情况?
  • @Joe 不,它没有。我已经先检查过了。它几乎立即返回(不到一毫秒)是的,在某些情况下它可以同步完成。当有未完成的通知时会发生这种情况。我还验证了让它永久返回 false 没有任何区别。 ------ @ZERO:如果这样做,我会感到非常惊讶。如果是这样,它的行为就像一个普通的同步处理程序。我认为 IAsyncResult 进入队列供 asp.net 监控。

标签: asp.net iis-7


【解决方案1】:

这是一篇解释您所见内容的博文:

http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx

和同伴帖子

http://blogs.msdn.com/b/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx

在集成管道模式下,使用默认配置,IIS7 将每个 CPU 限制为 12 个并发请求(不是线程)。您可以通过修改配置来更改此设置。

我放不下。我很确定这就是你所看到的。深入研究文章,我不是很喜欢他们所做的更改,因为它显然会导致这样的问题,但我该判断谁!

【讨论】:

  • 太棒了!非常感谢 - 至少我现在知道了!
【解决方案2】:

另一件事要检查。如果您的客户端不是实际的浏览器,而是另一个向您的服务器发出多个并发请求的应用程序,这可能会导致您的问题。

并发请求和会话状态

对 ASP.NET 会话状态的访问是每个会话独占的,这意味着如果两个不同的用户发出并发请求,则同时授予对每个单独会话的访问权限。但是,如果对同一个会话发出两个并发请求(通过使用相同的 SessionID 值),则第一个请求将获得对会话信息的独占访问权。第二个请求仅在第一个请求完成后执行。 (如果因为第一个请求超过了锁超时,信息上的独占锁被释放,第二个会话也可以获得访问权。)如果@Page指令中的EnableSessionState值设置为ReadOnly,则请求只读会话信息不会导致对会话数据的独占锁定。但是,会话数据的只读请求可能仍需要等待会话数据的读写请求设置的锁定清除。

【讨论】:

  • 是的,该应用程序不是浏览器。会话状态被禁用: in web.config
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-14
  • 1970-01-01
  • 2021-10-14
  • 2021-09-29
  • 1970-01-01
  • 2011-03-20
相关资源
最近更新 更多