Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - Все статьи »

Обсудить на форуме Обсудить на форуме

Пакетная компиляция в ASP.NET
В статье рассматриваются вопросы пакетной компиляции ASPX страниц и технические детали данного процесса.
В статье рассматриваются вопросы пакетной компиляции ASPX страниц и технические детали данного процесса.

 

Наверно многие замечали, что первое обращение к ASPX странице занимает значительно больше времени, чем последующие и при этом заметно повышенное потребление ресурсов Веб-сервера. Это ASP.NET производит т.н. динамическую компиляцию или компиляцию "на-лету" (on-the-fly). Она происходит автоматически, когда браузер запрашивает страницу с сервера. Очевидно, что хотелось бы иметь средство избежать подобных задержек. Далее я рассмотрю, что же предлагает ASP.NET для борьбы с этим, а так же приведу некоторые детали того, как происходит обработка запросов к страницам с точки зрения динамической компиляции.

Немного теории

Как известно, ASP.NET в отличие от ASP производит компиляцию (а не интерпретацию) ASPX страниц. При такой компиляции для каждой страницы или группы страниц создается сборка (assembly) - динамическая библиотека dll.

Замечу, что речь идет именно о страницах ASPX и серверных скриптах внутри этих страниц, а не о т.н. code behind файлах, которые должны быть заранее скомпилированы и размещены в папке BIN или глобальном кеше сборок (GAC - Global Assembly Cache). Использование code behind файлов является предпочтительным способом, так как позволяет добиться разделения кода и представления. К сожалению это не исключает компиляции ASPX страниц.

Сборка содержит MSIL (MicroSoft Intermediate Language) код, который в свою очередь перед фактическим исполнением компилируется в исполняемый код. Единица компиляции - вызываемый метод. Это т.н. JIT-компиляция. Соственно говоря, этим уже занимается не ASP.NET, а.NET Framework, так как с точки зрения Framework скомпилированная ASPX страница - это обычная сборка, содержащая несколько классов, поддерживающих определенные интерфейсы.

После JIT-компиляции исполняемый код метода кешируется и последующие обращения к этому методу происходят напрямую.

Таким образом имеются две области, в которых происходят задержки при обращении к ASPX странице:

- компиляция "на-лету"

- JIT-компиляция

Последнюю мы рассматривать не будем, а вот в процесс компиляции "на-лету" можно вмешаться.

Первый запрос страницы

ASP.NET определяет, что требуется компиляция страницы, в случае, если для нее нет сохраненной сборки или страница была изменена. Далее производятся две основные операции:

- разбор (parsing) страницы и генерация исходного кода. Данный код можно увидеть при включенной отладке (см. ниже "Как устроена страница").

- компилиция кода страницы и сохранение полученной сборки

 

Если страница уже была ранее скомпилирована, т.е. для нее есть соответствующая сборка, то данная сборка используется в качестве обработчика запрошенной страницы.

Давайте представим себе реальную ситуацию, когда Веб-сайт содержит несколько сотен или тысяч страниц. Что происходит, когда пользователь запрашивает страницу с сервера? Правильно - компиляция этой страницы. Теперь представьте, что сайт нагружен. Очевидно, что в этом случае время отклика сервера возрастает, а это не есть хорошо. Кстати - это касается и Веб-сервисов, но это немного другая история, так как здесь вмешиваются механизмы Reflection и сериализации.

Что же можно сделать, чтобы оптимизировать процесс динамической компиляции?

ASP.NET предлагает средство, называемое "пакетная компиляция" (batch compilation).

Пакетная компиляция

За процесс компиляции отвечает элемент конфигурации <compilation> файла web.config:

<configuration>
   <system.web>
      <compilation>
<compilation debug="true|false" 
             batch="true|false"
             batchTimeout="число секунд"
             defaultLanguage="язык" 
             maxBatchSize="максимальное число страниц на пакетную компиляцию"
             maxBatchGeneratedFileSize="максимальный размер 
		сгенерированного исходного файла в KB"
             tempDirectory="директория для временных файлов при компиляции">
</compilation>

 

Атрибут Значение Описание
Debug   Компиляция с отладочной информацией. По умолчанию false
  true Компиляция с отладочной информацией. Сохраняются исходные файлы на языке, указанном в атрибуте defaultLanguage.
Замечание: при включенной отладочной информации пакетная компиляция не производится
  false Компиляция без отладочной информации.
defaultLanguage   Язык, в который разбирается страница. По умолчанию vb, но Visual Studio.NET устанавливает его в c#
batch   Пакетная компиляция
  true Пакетная компиляция включена
  false Пакетная компиляция выключена
batchTimeout   Указывает тайм-аут, в секундах, для пакетной компиляции. Если компиляция не может быть выполнена за этот период, то компилятор возвращается к стандартному режиму компиляции для текущей страницы
maxBatchGeneratedFileSize   Максимальный размер сгенерированного исходного файла в KB
maxBatchFileSize   Максимальное кол-во страниц на одну пакетную компиляцию
tempDirectory   Директория для временных файлов при компиляции

Чтобы включить эту опцию, надо установить атрибут batch равным true, а debug равным false.

 

Что же произойдет в этом случае ? При запросе любой страницы из каталога, ASP.NET скомпилирует все страницы и создаст одну сборку. Т.е. вместо множества небольших dll (одна dll для одной страницы) получится одна большая dll для всех страниц в этом каталоге.

Здесь надо заметить, что пакетная компиляция производится на основе каталога, а не для всего Веб-приложения.

Очевидно преимущество такого подхода - не надо компилировать и разбирать страницу за страницей при первом к ним обращении. Но как говорится, бесплатный сыр бывает только в мышеловках. И данный подход - не исключение. Отрицательная сторона заключается в том, что такая компиляция занимает больше ресурсов сервера и может увеличить время отклика страниц, участвующих в такой компиляции. Но на это есть свое противоядие - "пред-пакетная" компиляция (pre-batch compilation). Т.е. перед тем, как кто-либо запросит любую страницу с сервера, Вы сами обращаетесь к любой странице, тем самым инициируя процесс пакетной компиляции и заставляя ASP.NET создать и закешировать все страницы сайта. Отсюда мораль - всегда перед передачей Веб-приложения в "производство" запрашивайте страницы из всех виртуальных каталогов.

 

Технические детали

Теперь немного о технических деталях. Любая страница ASPX при обращении к ней автоматически компилируется и попадает в:

%systemroot%/Microsoft.NET/Framework/<версия>/Temporary ASP.NET Files/<сайт>/nnnnn/mmmm

(nnnnn и mmmm - случайные последовательности).

Часть пути "%systemroot%/Microsoft.NET/Framework/<версия>/Temporary ASP.NET Files" может быть изменена с помощью атрибута tempDirectory

На моем компьютере - это:

C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files\TestProject\b5afd0e9\e951ffc7

В зависимости от значения атрибута batch, там будет находиться один или более файлов вида aabbcc.dll, а так же настройки для связывания (Test.aspx.mmmmm.xml).

Хитрость заключается в том, что в случае с batch=true, там будет всего одна dll, но в настройках связывания (напоминаю - это файлы вида Test.aspx.mmmmm.xml) будет указана одна и та же dll для всех страниц. Название dll выбирается случайным образом, аналогично выбору имени временного файла.

Также эта директория (а точнее поддиректория assembly) используется для т.н. "теневого" копирования используемых в Веб-приложении dll, что позволяет ASP.NET не блокировать их (вспомните ASP и COM).

Что происходит, если меняется одна страница

А теперь - самое интересное. Вы включили batch=true, произвели предкомпиляцию и наслаждаетесь быстрой работой сайта. В этот момент оказывается, что необходимо исправить одну страницу, скажем Test.aspx. Что происходит при следующем запросе этой страницы ?

ASP.NET компилирует ее и создает отдельную сборку со случайным именем, например xxyyzz.dll. Потом меняется настройка связывания, так что теперь ASP.NET знает: "код выполнения страницы Test.aspx находится не в aabbcc.dll, а в xxyyzz.dll". При этом в старой сборке остается код для страницы Test.aspx, но он не используется.

Как устроена страница или магия в действии

Если заглянуть в xxyyzz.dll с помощью утилиты ildasm (входит в состав .NET Framework SDK; также устанавливается с Visual Studio.NET), то можно убедиться, что в ней находится класс Test_aspx, который наследован от того класса, который вы использовали в качестве code behind (Test.aspx.cs, если таковой имелся, что не является обязательным; это класс, про который директива @Page в начале Вашей странице сообщает: Codebehind="Test.aspx.cs" Inherits="TestProject.Test"), который в свою очередь наследован от System.Web.UI.Page - базовый обработчик ASPX страниц (т.е. класс, поддерживающий интерфейс IHttpHandler и участвующий в конвеере запросов IIS/ASP.NET).

Для лучшего понимания процесса надо установить debug=true.

Замечу, что при этом перестанет работать пакетная компиляция, но это дает нам возможность увидеть, как наша страница выглядит в C#.

Тем, кто не собирается заниматься подобными изысканиями могу сообщить, что в основном там следующее:

- создание зависимости на исходный файл (Test.aspx), служащей для определения факта его изменения

- создание всех серверных элементов управления и инициализация базового класса (напомню, базовый класс - это Ваш code behind Test.aspx.cs). Собственно здесь и появляется та магическая связь между идентификаторами серверных элементов управления и Вашим кодом (а точнее полями Вашего класса)

- построение т.н. "дерева" элементов управления

Если запустить Task Manager, то можно заметить, как процесс csc.exe появляется и исчезает. Это запускается компилятор C#, который собственно и производит компиляцию исходного файла, полученного в результате разбора страницы.

После чего данная сборка используется конвеером ASP.NET для обработки запроса на ресурс Test.aspx.

Заключение

Несмотря на то, что при программировании ASP.NET не требуется знание работы среды исполнения, но в реальных проектах часто требуется тонкая настройка Веб-сервера, особенно под нагрузкой. Надеюсь, что информация в данной статье поможет разработчикам лучше понять работу ASP.NET и, возможно, решить некоторые проблемы, в частности, с ошибками по правам доступа, кешированием компонентов и т.п.


Может пригодится:


Автор: Дмитрий Мартынов
Прочитано: 3044
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (0)

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру