关于工人流程线程的困惑

时间:2012-03-04 20:01:37

标签: asp.net performance architecture thread-safety application-pool

尝试在浏览器的两个不同标签中打开以下页面。点击刷新按钮以避免从浏览器缓存中获取页面:

    protected void Page_Load(object sender, EventArgs e)
    {
        Thread.Sleep(10000);
        Response.Write(DateTime.Now.ToString());
    }

正如您所看到的,似乎每个请求都创建了一个线程,并且他们没有等待彼此没有获得锁定。

现在创建以下页面和GlobalCustomClass

GlobalCustomClass

public class GlobalCustomClass
    {
        public static string GlobalVariable
        {
            get;
            set;
        }
    }

Default.aspx的

protected void Page_Load(object sender, EventArgs e)
        {
            GlobalCustomClass.GlobalVariable = "Default page";
            Thread.Sleep(10000);
            Response.Write(DateTime.Now.ToString());
            Response.Write("<br />");
            Response.Write(GlobalCustomClass.GlobalVariable);
        }

Page2.aspx

 protected void Page_Load(object sender, EventArgs e)
        {
            Response.Write(DateTime.Now.ToString());
            Response.Write("<br />");
            GlobalCustomClass.GlobalVariable = "Page2";
            Response.Write(GlobalCustomClass.GlobalVariable);

        }

刷新默认页面,在10秒之前,刷新Page2 .... Default.aspx正在渲染“Page2”。是的,它不是线程安全的。

现在试试这个,在两个浏览器标签中打开以下页面:

    protected void Page_Load(object sender, EventArgs e)
    {
         Session["x"] = "ABC";
         Thread.Sleep(10000);
         Response.Write(DateTime.Now.ToString());
    }

现在似乎第一个线程锁定会话对象,另一个必须等​​待整整10秒!!

现在尝试第一种情况,但将Global.ascx放入项目......并说出什么,第一次线程锁定某事!!!!!

在实际应用中,通常需要访问需要线程安全的全局状态变量,如Sessions。

如果您的后端应用程序包含需要30秒才能呈现的报表。如果60个用户打开该报告,则用户编号61将等待半小时,直到页面加载到他的浏览器中!这是一个典型的线程饥饿!!我可能会被解雇:(

1)每个用户都在等待另一个用户完成他的请求。这应该使任何重页成为一个问题。因为它可以使整个Web应用程序响应迅速。 同意吗

2)如何解决这种情况?

3)在哪个主题下我应该研究一下?你知道一本好书吗?

由于

4 个答案:

答案 0 :(得分:4)

  

如果有60个用户打开该报告,则用户编号61将等待   半小时,直到页面加载到他的浏览器!!

这不是真的,因为锁只是每个会话,但不是全局的所有用户/会话。

由于您使用相同的浏览器来调用这两个页面,因此您也使用相同的ASP.NET会话(因为两个选项卡共享ASP.NET会话cookie)。如果您使用两个不同的浏览器来模拟两个用户,您将看到第二个用户将被阻止20秒。

此外,当然只有在使用会话状态时才会发生锁定。如果你想创建一个高性能的Web应用程序(有很多同时用户,或同时/异步请求),那么你应该尽可能地避免会话状态。

答案 1 :(得分:4)

如果您需要来自同一用户的并发请求,您可以

  1. 禁用会话状态或
  2. 在页面指令中将会话设置为ReadOnly。
  3. 显然,如果会话状态是ReadOnly,则无法写入,但您仍然可以阅读它以确定用户是谁等等。

答案 2 :(得分:2)

让我们来看看文档:

  

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

来自http://msdn.microsoft.com/en-us/library/ms178581.aspx

因此只有同一个用户才会被迫等待。锁存在,但仅限每个用户。

答案 3 :(得分:1)

  

每个用户都在等待另一个用户完成他的请求。应该   使任何重页成为问题。因为它可以制作整个网络   应用程序响应迅速。同意?

我不同意。假设您的网站页面只需要100毫秒即可执行,但支持1000个并发用户。根据您的逻辑,在最后一个请求完成之前需要100K ms。显然,在高流量网站上并非如此。

我怀疑ViewState上是否有任何锁定(为什么会有?它只与当前正在执行的页面实例相关)。

会话在页面生命周期的开始时被锁定,但只有在用户级别,它支持我的声明,这并不像你想象的那么大。还有ways around this

即使在.NET 1.1中,我曾经使用VS工具(Application Center Test)进行并发测试,而且 - 虽然流量肯定会减慢网站速度 - 但成千上万的昂贵请求并不会造成线性瓶颈描述

我认为你需要创建一个更强大的测试设置来产生结论性结果。