• ASP.net Session阻塞、Session锁、MVC Action请求阻塞问题



    会话Session

    • Session用于服务器端状态管理,使用Session之后,每个客户端都可以将实际的数据保存在服务器上,对于每个客户端的数据,将会生成一个对应的唯一的key(保存在客户端)。客户端与服务器端就是通过这个key来确认客户端的身份,通常这个key为SessionID。
    • 一般情况下,SessionID以Cookie的形式保存在浏览器中,在不使用Cookie的情况下,也可以将这个SessionID嵌入到访问网页的URL中。

    服务器端Session

    在页面对象或者HttpContext对象中,都有一个名为Session的属性,在一次会话中,它们引用的都是同一个对象。

    public HttpSessionState Session { get; }

    Session对象是HttpSessionState类的实例。Session是保存在服务器端的,对每个登录到网站的用户都有一份,是独有的,而其他用户无法共享。


    那么问题来了,来看看奇怪的阻塞。

    我们来看一个一需求: 需要实时的将服务器的运行状态输出到当前登陆的客户端,建立长连接并且作实时输出。 然后就有了下面这个Action。

    Boolean isOnline = true;
     
     public ActionResult Index()
     {
                #region 滚动条控制
    
                Response.Write("<html onclick="clearInterval(i_1);" ondblclick ="reInterval()"><head><title>服务器实时监控</title></head>");
                Response.Write("<script type="text/javascript">");
                Response.Write("function scrollWindow() { document.body.scrollTop = document.body.scrollHeight; }");
                Response.Write("function reInterval() { i_1 = setInterval('scrollWindow()', 50); }");
                Response.Write("i_1 = setInterval('scrollWindow()', 50);");
                Response.Write("scrollWindow();");
                Response.Write("</script> ");
                Response.Flush();
    
                #endregion
                
                Dictionary<int, string> dicColor = new Dictionary<int, string>() 
                {
                    {0,"#0000FF"},          // 蓝色
                    {1,"#FF3333"},          // 红色
                    {2,"#FFFF00"},          // 黄色
                    {3,"#FF3EFF"},
                    {4,"#0000FF"},
                    {5,"#0000FF"}
                };
                DebugCallback callback = new DebugCallback(delegate(int type, string str)
                {
                    if (dicColor.ContainsKey(type))
                    {
                        Response.Write("<span style = 'color:" + dicColor[type] + ";'>" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "--" + str + "</span>  <br />");
                    }
                    Response.Flush();
                });
    
                Log.AddCallBack(callback);
    
                while (isOnline)
                {
                    try
                    {
                        Response.Write("...<br>");
                        Response.Flush();
                    }
                    catch { }
                    System.Threading.Thread.Sleep(1000);
                    if (!Response.IsClientConnected)            // 连接关闭
                    {
                        Log.RemoveCallBack(callback);
                        Response.Write("</html>");
                        break;
                    }
                }
                return null;
            }
    View Code

    由于这个Action是一个长连接,它不会断开连接会一直处于请求的状态,这个时候当我们再请求同一个Session的其它的Action的时候,发现所有其它的Action都会处于Waiting状态……好吧,明明是异步并发请求,为何现在却成了“单线程”工作了呢?很明显有锁。


    原因

    • HttpSessionState来自于HttpModule的SessionStateModule。在每次请求处理过程中,HttpApplication的请求的处理管道中会检查当前请求的处理程序是否实现了接口IRequiresSessionState,如果实现的话,那么SessionStateModule将为这个请求分配HttpSessionState。同时SessionStateModule还负责SessionID的生成、Cookieless会话管理、从外部状态提供程序中检索会话数据以及将数据绑定到请求的调用上下文。
    • 如果页面请求设置一个读取器锁定,同一会话中同时处理的其他请求将无法更新会话状态,但是至少可以进行读取。如果页面请求为会话状态设置一个写入锁,那么所有其他页面都被阻止,无论他们是否要读取或写入内容。例如,如果同时有两段程序视图在同一个Session中写入内容,一段程序必须等到另一段程序完成后才能写入。在AJAX程序设计中,必须注意这种情况的发生。

    解决方法

    对于Asp.net MVC:

    可以为本Controller增加以下特性,但是本Controller都不能修改Session了,只能读取

    [SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

    对于Asp.net WebForm:

    在Web.config 文件里面添加

    EnableSessionState="ReadOnly" // 仅仅加载那个阻塞页面
    博文作者:番茄炒西红柿
    博文出处:http://www.cnblogs.com/fanqie-liuxiao/
    本文版权归作者和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作! 如果阅读了本文章,觉得有帮助,您可以为我的博文点击“推荐一下”!
  • 相关阅读:
    谁在TDD
    开源许可证简单总结
    【转】IIS HTTP500错误以及COM+应用程序8004e00f错误的解决方法
    [原]Linux平台Boost的编译方法
    [原]linux下格式化磁盘的相关问题
    [原]编译MongoDB,C++连接MongoDB测试
    [转]谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词(科普)
    [转]linux下如何查看文件编码格式及转换文件编码
    [原]linux(虚拟机)下安装MySQL
    [转]Linux下比较全面的监控工具dstat
  • 原文地址:https://www.cnblogs.com/fanqie-liuxiao/p/5702633.html
Copyright © 2020-2023  润新知