Usando um HTTPContext entre threads
usuário @ acessa a página spawn.aspx, que gera uma meia dúzia de threads, renderizando todas as páginas usando
((System.Web.IHttpHandler)instance).ProcessRequest(reference to spawn's HTTPContext);
Não se preocupe com o fato de o ASP.Net estar aparentemente enviando ao usuário 7 respostas para uma solicitação, essa parte é tratada e apenas uma resposta é enviad
O problema é que, em um ambiente de tráfego intenso (nosso ambiente de produção) com muitos threads (quad-quads), obtemos um erro:
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
Não podemos duplicá-lo em outro lugar. Meu colega de trabalho acredita que isso ocorre porque estou reutilizando o HTTPContext original e passando-o para os outros threads, e que não é seguro para threads.
Seguindo essa lógica, tentei criar um novo HTTPContext para passar para os threads. Mas partes dela aparentemente não "combinam". Especificamente, preciso obter o objeto Session no novo HTTPContext. Eu imagino que gostaria de obter outras partes também, como o Cache. Para o registro, HTTPContext.Current.Session.IsSynchronized é false.
As minhas perguntas são:
Você acha que o erro ocorre ao usar HTTPContext entre threads?Como posso corrigir isso?Se a correção estiver duplicando o HTTPContext para cada segmento, como posso obter a Sessão (e o Cache) para o novo? Solicitação e resposta vêm no ctor, mas a Sessão não é configuráveEdit: Mais detalhes
Então, voltando a esta declaração: "Não se preocupe com o fato de o ASP.Net estar aparentemente enviando ao usuário 7 respostas para uma solicitação, essa parte é tratada e apenas uma resposta é enviada." Grande fã de Raymond Chen, concordo com você: "Agora você tem dois problemas" é uma afirmação razoável na ausência de mais informaçõe
O que realmente está acontecendo é que estou criando um documento do Excel para enviar de volta. Na página spawn.aspx, ele está configurando algumas informações de estado, incluindo o fato de que está renderizando para o Excel e o objeto para o qual está fazendo a renderização. Cada página gerada obtém essas informações e será bloqueada até que seja a sua vez de renderizar no objeto. Se estiver literalmente assim:
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);
}
Mas todo o processamento até esse ponto - acesso ao banco de dados, hierarquia de controle, tudo o que é feito em paralelo. E há muito disso - o suficiente para paralisá-lo e, ao mesmo tempo, deixá-lo bloquear no Render, reduzirá o tempo total em mais da metad
E a melhor parte disso - nada tinha que ser reescrito para a renderização do Excel. Todos os controles sabem como se render para o Excel, e você pode visitar cada página gerada independentemente (esse é o "caso normal", na verdade - o relatório do Excel é apenas uma agregação de todas as páginas geradas
Então imaginei que o resultado final seria "você não pode fazer isso, precisa repensar a abordagem" - mas tive que pelo menos tentar, porque o fato de que tudo funciona tão bem sem duplicar nenhuma lógica ou código ou ter que abstrair algo é tão perfeito. E é apenas o multithreading que é o problema; se eu renderizar as páginas em série, tudo estará bem, apenas lent