.Net心得:多个ajax并发请求时,被Session锁定串行导致轮询

从上家公司就有碰到这种场景,一个页面有个ajax请求,如果后台要执行很久,那么后续的ajax请求,都会在浏览器里排队,直到第一个这被执行出来(或者超时),才会轮到后面的。

这个很坑,明明是异步并行的东西,几乎变成同步串行了,原先搜索过,没找到答案。今天突然在园里发现了一篇文章,解决了心中的困惑。

https://www.cnblogs.com/emrys5/p/aspnet-session-readonly.html

原来是Session的存在,导致默认是一个个按顺序执行的,如果没有Session,那表现出来的就是真正的ajax异步,互不影响。如果有了Session,即使你没在方法里修改或读取任何Session,它也是默认这样锁定的。

解决方法是在控制器类上加SessionState(SessionStateBehavior.ReadOnly),这样就可以了。但有两个疑问:

1、看名称是Session只读了,但我试了也可以修改Session。网上也有人说是可以改。

http://www.it1352.com/261342.html

  

2、有人说同一Action仍会串行,但我试了加了ReadOnly后,同一Action也是异步并行的。

原来SessionStateModule模块实现了一个写入锁,并对其进行排队处理,所以同一SESSION下的所有请求都会被串行执行。

解决方案也很简单,在页面上增加EnableSessionState="ReadOnly"指令即可。 当然,增加了这个指令后,这个页面也就不能修改SESSION值了。

衍生
GOOGLE的过程中,发现.NET MVC同样也有这个问题,其解决方案是在controller上增加特性[SessionState(SessionStateBehavior.ReadOnly)]

随手实验一番,不加以上特性时,在有SESSION的情况下,同SESSION的请求会被串行处理。增加SessionStateBehavior.ReadOnly后不同action中,请求会被并行处理,但是相同action仍然是串行处理的。
即使是Task<ActionResult>,任然无法逃脱串行执行的魔掌。

 

不管怎样,如果对Session没有特别要求的页面,又有未优化好SQL或代码的请求在,一时不好优化或推倒重来,那就可以尝试下这种特性。

网上也推荐不使用Session,改用JWT等前后端分离的。但很多旧项目还是基于Session的,这个任何公司都会有旧项目要维护,全做新项目是可遇不可求。

附上测试代码,标红的就是这句特性:

using System.Threading;
using System.Web.Mvc;
using System.Web.SessionState;

namespace TestAjaxPending.Controllers
{
    [SessionState(SessionStateBehavior.ReadOnly)]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult TestAjax6()
        {
            Thread.Sleep(6000);
            Session["LoginId"] = 6;
            return Json(new { Code = 6, LoginId =  Session["LoginId"] });
        }

        [HttpPost]
        public ActionResult TestAjax1()
        {
            Thread.Sleep(1000);
            Session["LoginId"] = 1;
            return Json(new { Code = 1, LoginId =  Session["LoginId"] });
        }
    }
}
using System.Web.Mvc;

namespace TestAjaxPending.Controllers
{
    public class LoginController : Controller
    {
        public ActionResult Login()
        {
            Session["LoginId"] = 99;
            return Json(new { Code = Session["LoginId"] }, JsonRequestBehavior.AllowGet);
        }
    }
} 
@{
    ViewBag.Title = "About";
}
<style>
    #result6 div { background-color: red; display: inline-block; height: 80px; margin: 10px;  width: 60px;}
    #result1 div { background-color: blue; display: inline-block; height: 80px; margin: 10px;  width: 60px;}
</style>
@section scripts{
    <script type="text/javascript">
        $(function () {
            $("#btn-request6").click(function () {
                $("#result6").empty();
                $.ajax({
                    url: "Home/TestAjax6",
                    type: "post",
                    success: function () {
                        $("#result6").append("<div></div>");
                    }
                });
            });

            $("#btn-request1").click(function () {
                $("#result1").empty();
                $.ajax({
                    url: "Home/TestAjax1",
                    type: "post",
                    success: function () {
                        $("#result1").append("<div></div>");
                    }
                });
            });

            $("#btn-login").click(function () {
                $.ajax({
                    url: "Login/Login",
                    type: "post",
                    success: function (x) {
                        alert('登录成功!');
                    }
                });
             });
        });
    </script>
}
<h3>
    模拟操作
</h3>
<div>
    <input type="button" value="模拟登录" id="btn-login" />
    <input type="button" value="模拟请求6S" id="btn-request6"/>
    <input type="button" value="模拟请求1S" id="btn-request1"/>

</div>
<h3>
    结果
</h3>
<div id="result6"></div>
<div id="result1"></div>

猜你喜欢

转载自www.cnblogs.com/liuyouying/p/10805418.html