usuario pulsa spawn.aspx página que a su vez genera una media docena de hilos, representando las páginas utilizando todaEl uso de un HttpContext través de hilos
((System.Web.IHttpHandler)instance).ProcessRequest(reference to spawn's HTTPContext);
No se preocupe por el hecho de que ASP.Net es aparentemente enviando al usuario 7 respuestas para 1 solicitud, esa parte se maneja y solo se envía una respuesta.
El problema es que, en un entorno de alto tráfico (nuestro entorno de producción) con muchos hilos (quad-quads) obtenemos un error:
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
No podemos duplicarlo en otro lugar. Mi compañero de trabajo cree que esto se debe a que estoy reutilizando el HTTPContext original y pasándolo a los otros hilos, y que no es Thread-Safe.
Siguiendo esta lógica, he intentado hacer un nuevo HTTPContext para pasar a los hilos. Pero algunas partes aparentemente no se "combinarán". Específicamente, necesito obtener el objeto Session en el nuevo HTTPContext. Me imagino que me gustaría tener otras partes también, como Cache. Para el registro HTTPContext.Current.Session.IsSynchronized es falso.
Mis preguntas son:
- ¿Cree que el error es el uso de HttpContext través de hilos?
- ¿Cómo puedo solucionarlo?
- Si la solución está duplicando el HTTPContext para cada subproceso, ¿cómo puedo obtener la sesión (y el caché) en el nuevo? Solicitud y respuesta vienen en el ctor, pero la sesión no es configurable.
Edit: Más detalles
Así que volviendo a esta declaración: "No se preocupe por el hecho de que ASP.Net es aparentemente enviando al usuario 7 respuestas durante 1 solicitud, esa parte se maneja y solo se envía una respuesta ". Gran admirador de Raymond Chen, estoy de acuerdo contigo: "Ahora tienes dos problemas" es una afirmación razonable en ausencia de más información.
Lo que sucede en realidad es que estoy compilando un documento de Excel para enviar de vuelta. En la página spawn.aspx está configurando cierta información de estado, incluido el hecho de que se está renderizando para sobresalir y el objeto para hacer la representación. Cada página generada obtiene esa información, y se bloqueará hasta que sea su turno de renderizar al objeto. Si, literalmente, tiene el siguiente aspecto:
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);
}
Pero todo el proceso hasta ese momento - el acceso de base de datos, control de jerarquía, todo lo que se hace en paralelo. Y hay mucho de eso, lo suficiente como para dividirlo en paréntesis y, al mismo tiempo, dejar que se bloquee en Render reducirá el tiempo general en más de la mitad.
Y la mejor parte es que no hay que reescribir nada para el renderizado en Excel. Todos los controles saben cómo renderizarse para sobresalir, y puede visitar cada página generada independientemente (ese es el 'caso normal' en realidad - el informe de Excel es solo una agregación de todas las páginas generadas.)
Así que pensé El resultado final iba a ser "no se puede hacer esto, se debe replantear el enfoque", pero al menos tuve que intentarlo, porque el hecho de que todo funciona tan bien sin duplicar lógica o código ni tener que abstraer nada es tan perfecto. Y ese es el único problema del multi-threading, si renderizo las páginas en serie todo está bien, solo lento.
Si este bloqueo probablemente será difícil de arreglar, la excepción de subprocesamiento que recibe es de la clase Page, que está mutando el contexto http, a menos que pueda anular la acción en la página que está haciendo esto, y coloque un bloqueo luego el la solución de bloqueo no funcionará. – meandmycode
Un gran comentario, estoy de acuerdo contigo. Mi preferencia sería pasar un objeto totalmente nuevo que derive parte de su información del contexto HTTP en el momento de la creación de las bandas de rodamiento. Eso sería a prueba de balas. –