• .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;   60px;}
        #result1 div { background-color: blue; display: inline-block; height: 80px; margin: 10px;   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>
  • 相关阅读:
    [转]iOS多线程编程之NSThread的使用
    IOS 本地通知
    IOS 使用程序外地图(IOS Map and google Map)
    syq小姐姐的分享的历年考试经验
    对拍——我认为的最简写法
    对拍——我目前可以找到的最简写法
    数论板子——来自Loi_black
    一些神奇的(优化)板子——来自Loi_black的博客
    马拉车——模版+KMP——模版
    国庆七天乐——第七天
  • 原文地址:https://www.cnblogs.com/liuyouying/p/10805418.html
Copyright © 2020-2023  润新知