Пользователь переходит на страницу spawn.aspx, которая порождает полдюжины потоков, отображая страницы, используя
((System.Web.IHttpHandler)instance).ProcessRequest(reference to spawn's HTTPContext);
Не беспокойтесь о том, что ASP.Net, по-видимому, отправляет пользователю 7 ответов на 1 запрос, эта часть обрабатывается и отправляется только один ответ.
Проблема в том, что в среде с высоким трафиком (наша среда производства) со многими потоками (четырехугольниками) мы получаем ошибку:
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. Я полагаю, я бы хотел добавить и другие части, такие как Кэш. Для записи HTTPContext.Current.Session.IsSynchronized имеет значение false.
Мои вопросы:
- Считаете ли вы, что ошибка связана с использованием HTTPContext между потоками?
- Как я могу это исправить?
- Если исправление дублирует HTTPContext для каждого потока, как я могу получить сеанс (и кэш) в новом? Запрос и ответ приходят в ctor, но сеанс не устанавливается.
Редактировать: Подробнее
Итак, возвращаясь к этому утверждению: «Не беспокойтесь о том, что ASP.Net, похоже, отправляет пользователю 7 ответов на 1 запрос, эта часть обрабатывается и отправляется только один ответ». Огромный поклонник Рэймонда Чена, я согласен с вами: «Теперь у вас две проблемы» - разумное утверждение в отсутствие какой-либо дополнительной информации.
На самом деле происходит то, что я создаю документ 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);
}
Но вся обработка до этого момента - доступ к базе данных, управление иерархией, все это выполняется параллельно. И его много - достаточно того, что его упорядочение, в то же время позволяя блокировать его в Render, сократит общее время более чем вдвое.
И лучшая его часть - ничего не нужно было переписывать для рендера Excel. Все элементы управления знают, как сделать себя лучше, и вы можете посещать каждую порожденную страницу независимо (на самом деле это «нормальный случай» - отчет Excel - это просто совокупность всех порожденных страниц.)
Итак, я решил, что конечным результатом будет «вы не можете сделать это, вам нужно переосмыслить подход» - но мне пришлось хотя бы попытаться, потому что тот факт, что все работает так хорошо, не дублируя никакой логики или любой код или необходимость что-то абстрагировать просто так совершенны. И проблема заключается только в многопоточности, если я последовательно отображаю страницы, все в порядке, просто медленно.