ASP.Net异步页面锁定了应用程序池-如何避免这种情况?

时间:2019-05-20 06:58:12

标签: c# asp.net multithreading asynchronous iis

我正在开发一个ASP.Net应用程序,该应用程序正在执行一些繁重的异步工作,并在工作过程中通过一些javascript代码立即通知客户端。

在测试过程中,我意识到它的工作非常好,直到发现其他问题为止。当单个异步页面打开并开始运行时,IIS将阻止(保留)所有其他以后的客户端请求,直到异步页面完成工作为止。 IIS接受连接(我想只是为了防止浏览器侧的连接超时),但是在异步页面完全完成之前,不发送任何内容。异步作业完成后,它将恢复流程将来的请求,并且一切恢复正常。

但是,这当然是有问题的。老实说,我没想到会这样,因为这就是为什么要使用线程,而不是阻止UI,对吧?

这是我为您开发的示例代码,用于测试谁对该主题感兴趣。您可以创建新项目,甚至将其添加到现有的asp.net应用程序之一。之后,只需转到/async.aspx,当它开始异步计数时,只需在浏览器中打开另一个标签页,然后开始请求同一域中的其他子页。您将体验到,最终网站将停止响应将来的请求,直到异步工作完成。

我说“最终”是因为 对于此简单示例代码 ,有时IIS会响应第一个到三个请求,然后进入“保留”状态。

但是,在我的主项目中,异步工作比依靠示例代码中的2个线程要重得多,因此,即使在我的工作开始时也无法加载第一页。

async.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="async.aspx.cs" Inherits="async.test.app.async" Async="true" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Async Test</title>
    <script>
        function updatePercent(id, p) {
            document.getElementById(id).innerText = p;
        }
        function allDone() {
            var labels = document.getElementsByClassName("percent");
            for (var i = 0; i < labels.length; i++)
                labels[i].innerText = "Completed!";
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <h1>Async test page</h1>
        <div>Server-side async task #1 percent is: <span id="percent1" class="percent"></span></div>
        <div>Server-side async task #2 percent is: <span id="percent2" class="percent"></span></div>
    </form>
</body>
</html>
<%
    //calling to start right here makes it sure to browser load up the content so far - using response.flush in StartAsyncWork()
    StartAsyncWork();
%>

async.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;

namespace async.test.app
{
    public partial class async : System.Web.UI.Page
    {

        ManualResetEvent[] MRE;
        object response_locker;

        protected void Page_Load(object sender, EventArgs e)
        {

        }

        public void StartAsyncWork()
        {

            //flush buffer first
            Response.Flush();

            response_locker = new object();

            //create first task (count to 20)
            ManualResetEvent mre1 = new ManualResetEvent(false);
            Thread Thread1 = new Thread(() => CountTo(mre1, "percent1", 20));

            //create second task (count to 30)
            ManualResetEvent mre2 = new ManualResetEvent(false);
            Thread Thread2 = new Thread(() => CountTo(mre2, "percent2", 30));

            //prepare waithandles
            MRE = new ManualResetEvent[] { mre1, mre2 };

            //start tasks
            Thread1.Start();
            Thread2.Start();

            //wait for all tasks to complete
            ManualResetEvent.WaitAll(MRE);

            Response.Write("<script>allDone();</script>");
            Response.Flush();

        }

        protected void CountTo(ManualResetEvent mre, string id, int countTo) //counts to 60
        {
            try
            {
                for (int i = 1; i <= countTo; i++)
                {
                    lock (response_locker)
                    {
                        Response.Write(string.Format("<script>updatePercent('{0}','{1}/{2}')</script>", id, i, countTo));
                        Response.Flush();
                    }
                    Thread.Sleep(1000);
                }

            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                mre.Set();
            }
        }

    }
}

0 个答案:

没有答案