跨线程使用HTTPContext

时间:2009-04-09 15:51:30

标签: asp.net multithreading httpcontext

用户点击页面spawn.aspx然后生成六个线程,使用

渲染页面
 ((System.Web.IHttpHandler)instance).ProcessRequest(reference to spawn's HTTPContext);

不要担心ASP.Net似乎正在向用户发送1个请求的响应,该部分被处理并且只发送一个响应。

问题是,在拥有许多线程(quad-quads)的高流量环境(我们的生产环境)中,我们收到错误:

System.IndexOutOfRangeException 
at System.collections.ArrayList.Add 
at System.Web.ResponseDependencyList.AddDependencies(String[] items, String argname, Boolean cloneArray, DateTime utcDepTime) 
at System.Web.ResponseDependencyList.AddDependencies(String[] items, String argname, Boolean cloneArray, String requestVritualPath)
at System.Web.UI.Page.AddWrappedFileDependencies(Object virtualFileDependencies) 
at ASP.spawned_page_no_1_aspx.FrameworkInitialize()
at System.Web.UI.Page.ProcessRequest

我们不能在其他地方复制它。我的同事认为这是因为我正在重用原始的HTTPContext并将其传递给其他线程,并且它不是线程安全的。

遵循这个逻辑,我尝试将新的HTTPContext传递给线程。但它的一部分似乎不会“结合”。具体来说,我需要将Session对象放入新的HTTPContext中。我想我也想要其他部分,比如Cache。对于记录,HTTPContext.Current.Session.IsSynchronized为false。

我的问题是:

  1. 您认为错误来自跨线程使用HTTPContext吗?
  2. 我该如何解决?
  3. 如果修复程序复制了每个线程的HTTPContext,我如何将Session(和Cache)转换为新的?请求和响应来自ctor,但Session不可设置。
  4. 修改:更多详情

    回到这句话:“不要担心ASP.Net似乎正在向用户发送1个请求的响应,该部分被处理,只有一个响应被发送。” Raymond Chen的巨大粉丝,我同意你的观点:“现在你有两个问题”,如果没有更多的信息,这是一个合理的陈述。

    实际发生的是我正在构建一个Excel文档以便发回。在spawn.aspx页面中,它设置了一些状态信息,包括它渲染为excel的事实,以及进行渲染的对象。每个衍生的页面都会获取该信息,并将阻止它们轮到渲染到该对象。如果字面上看起来像这样:

     protected override void Render(System.Web.UI.HtmlTextWriter writer)
     {
        if (this.RenderToExcel)
        {
          Deadlocker.SpinUntilCurrent(DeadLockToken);
          RenderReport(this, this.XLSWriter);
          Deadlocker.Remove(DeadLockToken);
        }
        else
          base.Render(writer);
     }
    

    但到目前为止的所有处理 - 数据库访问,控制层次,所有这些都是并行完成的。并且它有很多 - 足够的,它仍然让它阻止渲染它的一部分将把总体时间减少一半以上。

    最好的部分是 - 没有必要为Excel渲染重写。所有控件都知道如何将自己渲染为excel,并且您可以独立访问每个衍生页面(实际上是'正常情况' - excel报告只是所有衍生页面的聚合。)

    所以我认为最终的结果将是“你不能这样做,你需要重新考虑这种方法” - 但我必须至少尝试一下,因为事实上一切都很好,没有重复任何逻辑或任何代码或必须抽象的东西都是如此完美。并且它只是多线程问题,如果我连续渲染页面一切都很好,只是很慢。

4 个答案:

答案 0 :(得分:4)

虽然HttpContext旨在处理非特定于线程的上下文(因为http上下文可以在一个线程上启动并在另一个线程上完成),但它不是隐式线程安全的。

基本上问题是你正在做一些非预期的事情,这些请求通常是多个,每个请求都有自己分配的HttpApplication来完成请求,每个请求都有自己的HttpContext。

我真的会尝试让asp.net基础设施委托自己的请求。

答案 1 :(得分:2)

你的同事是对的,如果一个线程锁定一个资源而另一个线程试图使用它,那么你的线程池就会繁荣!效果不是很好。大多数人通过创建新对象并将它们传递给参数化线程来解决这个问题。如果您绝对需要使用相同的对象,那么您必须实现一些代码,首先检查资源是否被另一个线程使用,然后等待一段时间再次检查。一个例子是创建一个总是首先检查的IsInUse bool,然后你的线程在使用该资源时将其设置为true,然后在完成时将其设置为false,防止其他线程尝试使用底层资源(您的httpContext) 。我希望这有帮助。

答案 2 :(得分:1)

由于HttpContext是.Net库的一部分,我希望所有静态函数都是线程安全的,但是在调用对象的同一个实例时,任何非静态成员都不是线程安全的。所以希望下次你会期望跨线程共享HttpContext实例会有问题。

有没有办法可以解除你需要从HttpContext并行执行的操作?如果他们只是加载数据并写入CSV格式,那么该代码就没有必要依赖于ASP.NET用户控件或页面生命周期。删除该依赖项后,您可以使用异步HttpHandler实现该页面,在IHttpHandler.BeginProcessingRequest()和IHttpHandler.EndProcessingRequest()之间运行并行操作。

答案 3 :(得分:1)

我会确保您在访问HttpContext.Current.Items集合时,在HttpContext.Current.Items.SyncRoot对象上使用Monitor lock(C#)/ SyncLock(VB)块来包装您的调用。< / p>