Невероятно, насколько легко писать веб-приложения с использованием ASP.NET. Из-за этой простоты многие разработчики не тратят время на структурирование своих приложений для повышения производительности. В этой статье я приведу 10 советов по написанию высокопроизводительных веб-приложений. Но я бы не стал ограничивать эти предложения приложениями ASP.NET, поскольку эти приложения являются лишь частью веб-приложения. Эта статья не является исчерпывающим руководством по настройке производительности веб-приложений — целая книга не сможет легко охватить эту тему. Считайте эту статью отличной отправной точкой.
До того, как я стал трудоголиком, мне нравилось скалолазание. Перед любым большим восхождением я начинаю внимательно просматривать маршруты в путеводителях и читать рекомендации предыдущих посетителей. Но независимо от того, насколько хорош гид, вам понадобится настоящий опыт скалолазания, прежде чем пытаться совершить особенно сложное восхождение. Точно так же вы можете научиться писать высокопроизводительные веб-приложения только тогда, когда вам придется решать проблемы с производительностью или запускать сайт с высокой пропускной способностью.
Мой личный опыт я получил от работы менеджером инфраструктурных программ в подразделении ASP.NET в Microsoft, где я управлял сайтом www.ASP.NET и помогал проектировать серверы сообщества, один из нескольких хорошо известных
Приложения ASP.NET (форумы ASP.NET, .Text и nGallery объединены в одну платформу). Я уверен, что некоторые советы, которые помогли мне, помогут и вам.
Вам следует рассмотреть возможность разделения вашего приложения на несколько логических уровней. Возможно, вы слышали термин «3-уровневая (или n-уровневая) физическая архитектура». Обычно это предписанные архитектурные подходы, которые физически разделяют функциональность между процессами и/или оборудованием. Когда системе необходимо расшириться, можно легко добавить больше оборудования. Однако скачки процессов и машин приводят к снижению производительности, и этого следует избегать. Поэтому, если возможно, попробуйте запускать страницы ASP.NET и связанные с ними компоненты вместе в одном приложении.
Из-за разделения кода и границ между уровнями использование веб-служб или удаленного взаимодействия приведет к снижению производительности на 20 % и более.
Уровень данных немного отличается, потому что обычно лучше иметь оборудование, выделенное для базы данных. Однако стоимость перехода процесса к базе данных по-прежнему высока, поэтому производительность уровня данных — это первый вопрос, который следует учитывать при оптимизации кода.
Прежде чем приступать к исправлениям производительности вашего приложения, сначала убедитесь, что вы профилировали свое приложение, чтобы выявить конкретные проблемы. Ключевые счетчики производительности, например, представляющие процент времени, необходимое для выполнения сборки мусора, также полезны для определения того, где приложение проводит основное время. Однако то, куда тратится время, часто бывает очень неинтуитивным.
В этой статье описываются два типа улучшений производительности: большие оптимизации (например, использование кэширования ASP.NET) и небольшие повторяющиеся оптимизации. Эти небольшие оптимизации иногда особенно интересны. Вы вносите небольшое изменение в свой код и выигрываете много-много времени. При значительной оптимизации вы можете увидеть значительный скачок общей производительности. С помощью небольших оптимизаций вы можете сэкономить всего несколько миллисекунд для конкретного запроса, но если суммировать все запросы каждый день, это может стать огромным улучшением.
Производительность уровня данных
Когда дело доходит до настройки производительности приложения, есть тест, который вы можете использовать, чтобы расставить приоритеты в своей работе: имеет ли код доступ к базе данных? Если да, то на какой частоте? Обратите внимание, что этот же тест можно применить и к коду, использующему веб-службы или удаленное взаимодействие, но в данной статье они не рассматриваются.
Если запрос к базе данных необходим для определенного пути кода и вы считаете, что вам нужно сначала оптимизировать другие области (например, манипуляции со строками), остановитесь, а затем выполните эту проверку с помощью щупа. Если ваши проблемы с производительностью не являются серьезными, рекомендуется потратить некоторое время на оптимизацию времени, затрачиваемого на работу с базой данных, объема возвращаемых данных и частоты обращений к базе данных и обратно.
Учитывая эту общую информацию, давайте рассмотрим десять советов, которые могут помочь улучшить производительность приложения. Сначала я расскажу об изменениях, которые могут иметь наибольшее значение.
Совет 1. Возвращайте несколько наборов результатов.
Внимательно посмотрите код своей базы данных, чтобы увидеть, есть ли в базе данных несколько путей запроса. Каждое такое обращение уменьшает количество запросов в секунду, которые может обслуживать приложение. Возвращая несколько наборов результатов в одном запросе к базе данных, вы можете сэкономить общее время, необходимое для взаимодействия с базой данных. В то же время это также делает систему более масштабируемой за счет сокращения работы сервера базы данных по управлению запросами.
Хотя для возврата нескольких наборов результатов можно использовать динамический SQL, я предпочитаю использовать хранимые процедуры. Существуют некоторые споры относительно того, должна ли бизнес-логика размещаться в хранимой процедуре, но я думаю, что было бы лучше, если бы логика в хранимой процедуре могла ограничивать возвращаемые данные (уменьшая размер набора данных, сокращая время, затрачиваемое на обработку). сети, без необходимости просеивать данные логического уровня), этому следует отдавать предпочтение.
При заполнении строго типизированного бизнес-класса с помощью экземпляра SqlCommand и его метода ExecuteReader вы можете переместить указатель набора результатов вперед, вызвав NextResult. На рис. 1 показан пример сеанса с использованием классов типов для заполнения нескольких списков ArrayList. Возврат из базы данных только тех данных, которые вам нужны, еще больше уменьшит выделение памяти на сервере.
Рис. 1. Извлечение нескольких наборов результатов из DataReader
// читаем первый набор результатов
reader = command.ExecuteReader()
// считываем данные из этого набора результатов
в то время как (читатель.Читать()) {
поставщики.Добавить(PopulateSupplierFromIDataReader(читатель));
}
// читаем следующий набор результатов
reader.NextResult();
// считываем данные из второго набора результатов
в то время как (читатель.Читать()) {
Products.Add(PopulateProductFromIDataReader(читатель));
}
Совет 2. Доступ к данным с разбивкой на страницы
У ASP.NET DataGrid есть приятная функция: поддержка разбивки данных на страницы. Если в DataGrid включено разбиение по страницам, одновременно отображается фиксированное количество записей. Кроме того, в нижней части DataGrid отображается пользовательский интерфейс подкачки для облегчения навигации между записями. Пользовательский интерфейс разбиения на страницы позволяет перемещаться вперед и назад по отображаемым данным и отображает фиксированное количество записей одновременно.
Также есть небольшой нюанс. Разбивка на страницы с использованием DataGrid требует, чтобы все данные были привязаны к сетке. Например, если вашему уровню данных необходимо вернуть все данные, DataGrid будет фильтровать все отображаемые записи на основе текущей страницы. Если при постраничном просмотре DataGrid возвращается 100 000 записей, для каждого запроса отбрасывается 99 975 записей (при условии, что размер страницы равен 25 записям). Когда количество записей увеличивается, производительность приложения снижается, поскольку с каждым запросом необходимо отправлять все больше и больше данных.
Отличный способ написать более эффективный код нумерации страниц — использовать хранимые процедуры. На рис. 2 показан пример хранимой процедуры для разбиения по страницам таблицы Orders в базе данных Northwind. Короче говоря, все, что вам нужно сделать на этом этапе, — это передать индекс страницы и ее размер. Затем вычисляется и возвращается соответствующий набор результатов.
Рис. 2. Пролистывание таблицы заказов
СОЗДАТЬ ПРОЦЕДУРУ Northwind_OrdersPaged
(
@PageIndex целое,
@PageSize целое число
)
КАК
НАЧИНАТЬ
ОБЪЯВИТЬ @PageLowerBound int
ОБЪЯВИТЬ @PageUpperBound int
DECLARE @RowsToReturn int
— сначала установите количество строк
SET @RowsToReturn = @PageSize * (@PageIndex + 1)
SET ROWCOUNT @RowsToReturn
— устанавливает границы страницы.
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
— создать временную таблицу для хранения выбранных результатов.
СОЗДАТЬ ТАБЛИЦУ #PageIndex
(
IndexId int IDENTITY (1, 1) НЕ НУЛЬ,
OrderID целое число
)
-- Вставляем во временную таблицу
ВСТАВИТЬ В #PageIndex (OrderID)
ВЫБИРАТЬ
ID заказа
ОТ
Заказы
ЗАКАЗАТЬ ПО
OrderID DESC
– общее количество возвращенных товаров.
SELECT COUNT(OrderID) FROM Orders
– возврат постраничных результатов.
ВЫБИРАТЬ
О.*
ОТ
Приказы О,
#PageIndex Индекс страницы
ГДЕ
O.OrderID = PageIndex.OrderID И
PageIndex.IndexID > @PageLowerBound И
PageIndex.IndexID < @PageUpperBound
ЗАКАЗАТЬ ПО
PageIndex.IndexID
END
На сервере сообщества мы написали элемент управления сервером подкачки для выполнения всех подкачек данных. Как вы увидите, я использую концепцию, описанную в совете 1, для возврата двух наборов результатов из хранимой процедуры: общего количества записей и запрошенных данных.
Общее количество возвращаемых записей может варьироваться в зависимости от выполненного запроса. Например, предложение WHERE можно использовать для ограничения возвращаемых данных. Чтобы рассчитать общее количество страниц, отображаемых в пользовательском интерфейсе с разбивкой на страницы, вы должны знать общее количество возвращаемых записей. Например, если всего имеется 1 000 000 записей и вы хотите использовать предложение WHERE для фильтрации до 1 000 записей, логике подкачки необходимо знать общее количество записей, чтобы правильно отобразить пользовательский интерфейс подкачки.
Совет 3 — Пул соединений
Настройка TCP-соединения между веб-приложением и SQL Server может оказаться очень ресурсоемкой операцией. Разработчики Microsoft уже некоторое время могут использовать пул соединений, что позволяет им повторно использовать соединения с базой данных. Вместо того, чтобы устанавливать новое TCP-соединение для каждого запроса, они устанавливают новое соединение только тогда, когда в пуле соединений нет соединений. Когда соединение закрывается, оно возвращается в пул соединений, где поддерживает соединение с базой данных, а не полностью разрушает TCP-соединение.
Конечно, нужно быть осторожным, если у вас возникли негерметичные соединения. Когда вы закончите использовать соединения, обязательно закройте их. Повторим: что бы кто ни говорил о сборке мусора в Microsoft® .NET Framework, обязательно вызывайте Close или Dispose для соединения, когда закончите его использовать. Не доверяйте среде общего языка (CLR) очищать и закрывать соединения за вас в заранее определенное время. Хотя CLR в конечном итоге уничтожит класс и принудительно закроет соединение, нет никакой гарантии, когда действительно произойдет сборка мусора объекта.
Чтобы оптимально использовать пул соединений, необходимо соблюдать некоторые правила. Сначала откройте соединение, выполните операцию, затем закройте соединение. Если необходимо, открывайте и закрывайте соединение несколько раз за запрос (предпочтительно применяя совет 1), но не держите соединение открытым все время и передавайте его внутрь и наружу, используя различные методы. Во-вторых, используйте ту же строку подключения (и тот же идентификатор потока, если используется встроенная проверка подлинности). Если вы не используете одну и ту же строку подключения (например, настроив строку подключения на основе вошедшего в систему пользователя), вы не получите того же значения оптимизации, которое предоставляет пул соединений. Если вы используете встроенную аутентификацию, а также выдаете себя за большое количество пользователей, эффективность пула соединений также значительно снизится. Счетчики производительности данных .NET CLR могут быть полезны при попытке отследить любые проблемы с производительностью, связанные с объединением пулов соединений.
Всякий раз, когда ваше приложение подключается к ресурсу, например к базе данных, работающей в другом процессе, вам следует оптимизировать его, сосредоточив внимание на времени, необходимом для подключения к этому ресурсу, времени, необходимом для отправки или получения данных, а также на количестве обращений туда и обратно. Оптимизация любого вида переключения процессов в вашем приложении — это первый шаг к повышению производительности.
Уровень приложения содержит логику для подключения к уровню данных и преобразования данных в значимые экземпляры классов и бизнес-процессы. Например, сервер сообщества, на котором вы хотите заполнить коллекцию «Форумы» или «Темы», применить там бизнес-правила (такие как разрешения) и, самое главное, выполнить там логику кэширования;
Совет 4 — API кэширования ASP.NET
Прежде чем писать строку кода приложения, первое, что нужно сделать, — это структурировать уровень приложения, чтобы максимально использовать возможности кэширования ASP.NET.
Если ваш компонент должен работать в приложении ASP.NET, вам нужно только включить ссылку на System.Web.dll в проект приложения. Если вам нужно получить доступ к кешу, используйте свойство HttpRuntime.Cache (этот объект также доступен через Page.Cache и HttpContext.Cache).
Существует несколько правил кэширования данных. Во-первых, если данные, вероятно, будут использоваться несколько раз, это хорошая альтернатива использованию кэширования. Во-вторых, если данные являются общими и не относятся к конкретному запросу или пользователю, это также хороший кандидат для кэширования. Если данные относятся к пользователю или запросу, но имеют длительный срок службы, их все равно можно кэшировать, но это может использоваться не очень часто. В-третьих, часто упускаемое из виду правило заключается в том, что иногда можно кэшировать слишком много данных. Обычно на компьютере x86, чтобы уменьшить вероятность ошибок нехватки памяти, вам нужно запускать процессы с размером не более 800 МБ личных байтов. Поэтому кеш должен иметь предел. Другими словами, вы можете повторно использовать результат вычисления, но если это вычисление принимает 10 параметров, вы можете попытаться кэшировать 10 перестановок, что может вызвать у вас проблемы. Одним из наиболее распространенных запросов на поддержку ASP.NET являются ошибки нехватки памяти, вызванные чрезмерным кэшированием, особенно для больших наборов данных.
Кэширование имеет несколько замечательных функций, о которых вам нужно знать. Во-первых, в кэше реализован наименее используемый алгоритм, позволяющий ASP.NET принудительно очищать кэш — автоматически удаляя неиспользуемые элементы из кэша — когда память работает менее эффективно. Во-вторых, кеш поддерживает просроченные зависимости, срок действия которых может быть истечен принудительно. Эти зависимости включают время, ключи и файлы. Часто используется время, но в ASP.NET 2.0 представлен новый, более мощный тип инвалидации: инвалидация кэша базы данных. Это относится к автоматическому удалению элементов в кэше при изменении данных в базе данных. Дополнительные сведения о признании недействительными кэша базы данных см. в колонке Dino Esposito Cutting Edge в журнале MSDN Magazine за июль 2004 г. Чтобы понять архитектуру кэша, см. диаграмму ниже.
![]() |
Совет 6 — Фоновая обработка
Путь к коду должен быть максимально быстрым, верно? Могут возникнуть ситуации, когда вы почувствуете, что задача, выполняемая при каждом запросе или каждые n запросов, требует большого количества ресурсов. Отправка электронных писем или анализ и проверка входящих данных — вот некоторые примеры.
При анализе форумов ASP.NET 1.0 и перепроектировании содержимого, составляющего сервер сообщества, мы обнаружили, что добавление новых путей к коду публикации происходит очень медленно. При каждом добавлении нового сообщения приложению сначала необходимо убедиться в отсутствии дублирующих сообщений, затем оно должно проанализировать сообщение с помощью фильтра «плохих слов», проанализировать размещенный смайлик-символ, пометить и проиндексировать сообщение, а также добавить опубликовать по запросу. Перейдите в соответствующую очередь, проверьте вложение и после окончательной публикации немедленно отправьте уведомление по электронной почте всем подписчикам. Очевидно, что здесь задействовано очень многое.
После исследования выяснилось, что большая часть времени тратилась на логику индексации и отправку электронных писем. Индексирование сообщений — очень трудоемкая операция, и было обнаружено, что встроенная функция System.Web.Mail подключается к серверу SMYP, а затем непрерывно отправляет электронные письма. По мере увеличения количества подписчиков на определенную публикацию или тематическую область выполнение функции AddPost занимает все больше и больше времени.
Индексирование электронной почты не требуется для каждого запроса. В идеале мы хотели бы выполнить эту операцию в пакетном режиме, индексируя 25 публикаций за раз или отправляя все электронные письма каждые пять минут. Мы решили использовать код, который мы ранее использовали для прототипирования аннулирования кэша данных, который использовался для того, что в конечном итоге попало в Visual Studio® 2005.
Класс Timer в пространстве имен System.Threading очень полезен, но не очень известен в .NET Framework, по крайней мере, среди веб-разработчиков. После создания этот класс Timer будет вызывать указанный обратный вызов с настраиваемым интервалом для потока в ThreadPool. Это означает, что вы можете настроить выполнение своего кода без входящих запросов к приложению ASP.NET, что идеально подходит для фоновой обработки. В этом фоновом процессе вы также можете выполнять такие операции, как индексирование или отправка электронных писем.
Однако у этой технологии есть несколько проблем. Если домен приложения удален, этот экземпляр таймера перестанет генерировать свои события. Кроме того, поскольку в среде CLR существует жесткий стандарт количества потоков на процесс, могут возникнуть ситуации, когда сервер сильно загружен, когда у таймера может не быть потоков для завершения, что в некоторой степени приведет к задержкам. ASP.NET пытается свести к минимуму вероятность этого, сохраняя определенное количество потоков, доступных в процессе, и используя только часть общего числа потоков для обработки запросов. Однако это может стать проблемой, если у вас много асинхронных операций.
Здесь недостаточно места для этого кода, но вы можете скачать читаемый пример на сайте www.rob-howard.net. Ознакомьтесь со слайдами и демонстрациями презентации Blackbelt TechEd 2004.
Совет 7 — Кэширование вывода страниц и прокси-серверы
ASP.NET — это ваш уровень представления (или должен быть вашим уровнем представления); он состоит из страниц, пользовательских элементов управления, серверных элементов управления (HttpHandlers и HttpModules) и контента, который они генерируют. Если у вас есть страница ASP.NET, которая генерирует выходные данные (HTML, XML, изображения или любые другие данные), и когда вы запускаете этот код при каждом запросе, он генерирует один и тот же результат, тогда у вас есть инструмент, который можно использовать для отличная альтернатива кэшированию вывода страниц.
Добавьте эту строку содержимого в верхнюю часть страницы <%@ Page OutputCache VaryByParams="none" Duration="60" %>
Вы можете эффективно сгенерировать выходные данные для этой страницы один раз, а затем повторно использовать их несколько раз в течение до 60 секунд, после чего страница будет выполнена повторно, а выходные данные снова будут добавлены в кэш ASP.NET. Этого поведения также можно добиться с помощью некоторых низкоуровневых программных API. Существует несколько настраиваемых параметров кэширования вывода, например только что упомянутое свойство VaryByParams. VaryByParams просто запрашивается, но также позволяет указать параметры HTTP GET или HTTP POST для изменения записей кэша. Например, просто установите VaryByParam="Report" для кэширования вывода для default.aspx?Report=1 или default.aspx?Report=2. Дополнительные параметры можно указать, указав список, разделенный точкой с запятой.
Многие люди не знают, что при использовании кэширования вывода страницы ASP.NET также генерируют некоторые HTTP-заголовки, расположенные после сервера кэширования, например те, которые используются Microsoft Internet Security and Acceleration Server или Akamai. После установки заголовка HTTP-кеша документы могут кэшироваться на этих сетевых ресурсах, а запросы клиентов могут удовлетворяться без возврата на исходный сервер.
Таким образом, использование кэширования вывода страниц не повысит эффективность вашего приложения, но может снизить нагрузку на сервер, поскольку последующие технологии кэширования кэшируют документ. Конечно, это может быть просто анонимный контент; как только он перейдет в нисходящий поток, вы больше никогда не увидите эти запросы и больше не сможете выполнять аутентификацию, чтобы предотвратить доступ к нему.
Совет 8. Запустите IIS 6.0 (просто используйте его для кэширования ядра)
Если вы не используете IIS 6.0 (Windows Server? 2003), вы упускаете некоторые значительные улучшения производительности веб-серверов Microsoft. В совете 7 я обсуждал кэширование вывода. В IIS 5.0 запросы проходят через IIS, а затем в ASP.NET. Когда дело доходит до кэширования, HttpModule в ASP.NET получает запрос и возвращает содержимое кэша.
Если вы используете IIS 6.0, вы обнаружите небольшую приятную функцию, называемую кэшем ядра, которая не требует каких-либо изменений кода в ASP.NET. Когда ASP.NET выполняет запрос на кэширование вывода, кэш ядра IIS получает копию кэшированных данных. Когда запрос поступает от сетевого драйвера, драйвер уровня ядра (без переключения контекста в пользовательский режим) получает запрос, сбрасывает кэшированные данные в ответ, если они кэшированы, а затем завершает выполнение. Это означает, что при использовании кэширования в режиме ядра с кэшированием вывода IIS и ASP.NET вы увидите невероятные результаты в производительности. Во время разработки ASP.NET в Visual Studio 2005 я был менеджером программы, ответственным за производительность ASP.NET. Разработчики выполняют конкретную работу, но я вижу всю отчетность, которая поступает каждый день. Результаты кэширования режима ядра всегда наиболее интересны. Наиболее распространенной характеристикой является то, что сеть переполнена запросами/ответами, в то время как IIS работает с загрузкой ЦП лишь около 5%. Это шокирует! Конечно, есть и другие причины использовать IIS 6.0, но кэширование в режиме ядра является наиболее очевидным.
Совет 9 — Используйте сжатие Gzip
Хотя использование gzip не обязательно снижает производительность сервера (поскольку вы можете заметить увеличение загрузки ЦП), использование сжатия gzip может уменьшить количество байтов, отправляемых сервером. Это приводит к ощутимому увеличению скорости страницы и снижению использования полосы пропускания. В зависимости от отправляемых данных, степени их сжатия и поддержки клиентского браузера (IIS будет отправлять содержимое, сжатое с помощью gzip, только клиентам, которые поддерживают сжатие gzip, например Internet Explorer 6.0 и Firefox), ваш сервер может обслуживать Больше запросов. Фактически, почти каждый раз, когда вы уменьшаете объем возвращаемых данных, вы увеличиваете количество запросов в секунду.
Сжатие Gzip встроено в IIS 6.0, и его производительность намного выше, чем сжатие gzip, используемое в IIS 5.0, что является хорошей новостью. К сожалению, при попытке включить сжатие gzip в IIS 6.0 вы не сможете найти этот параметр в диалоговом окне «Свойства» IIS. Команда IIS встроила в сервер отличную функциональность gzip, но забыла включить административный интерфейс для ее включения. Чтобы включить сжатие gzip, вам придется покопаться в настройках конфигурации XML IIS 6.0 (чтобы не потерять сердце). Кстати, спасибо Скотту Форсайту из OrcsWeb за то, что он помог мне поднять эту проблему с сервером www.asp.net, размещенным на OrcsWeb.
В этой статье не описываются эти шаги. Прочтите статью Брэда Уилсона на сайте IIS6 Compression. Также имеется статья базы знаний о включении сжатия для ASPX в разделе Включение сжатия ASPX в IIS. Однако следует отметить, что из-за некоторых особенностей реализации динамическое сжатие и кэширование ядра не могут существовать одновременно в IIS 6.0.
Совет 10 — Состояние представления управления сервером
Состояние просмотра — интересное название для ASP.NET, которое хранит некоторые данные о состоянии в скрытых полях вывода сгенерированной страницы. Когда страница отправляется обратно на сервер, сервер может анализировать, проверять и применять эти данные состояния просмотра обратно в дерево управления страницей. Состояние просмотра — очень мощная функция, поскольку она позволяет сохранять состояние на клиенте и не требует использования файлов cookie или памяти сервера для сохранения этого состояния. Многие серверные элементы управления ASP.NET используют состояние просмотра для сохранения параметров, созданных во время взаимодействия с элементами страницы, например для сохранения текущей страницы, которая отображается при разбиении данных на страницы.
Однако использование состояния просмотра также имеет некоторые недостатки. Во-первых, это увеличивает общую нагрузку на страницу каждый раз, когда она обслуживается или запрашивается. Дополнительные издержки также возникают при сериализации или десериализации данных состояния представления, отправляемых обратно на сервер. Наконец, состояние просмотра увеличивает выделение памяти на сервере.
Некоторые серверные элементы управления имеют тенденцию чрезмерно использовать состояние представления, даже если оно не нужно, наиболее известным из которых является DataGrid. По умолчанию свойство ViewState включено, но вы можете отключить его на уровне элемента управления или страницы, если оно вам не нужно. Внутри элемента управления просто установите для свойства EnableViewState значение false или установите его глобально на странице, используя следующий параметр:
<%@ Страница EnableViewState="false" %>
Если вы не отправляете страницу обратно или всегда заново создаете элементы управления на странице при каждом запросе, вам следует отключить состояние просмотра на уровне страницы.
Я дал вам несколько советов, которые считаю полезными при написании высокопроизводительных приложений ASP.NET. Как я упоминал ранее в этой статье, это предварительное руководство, а не последнее слово о производительности ASP.NET. (Информацию об улучшении производительности приложений ASP.NET см. в разделе Улучшение производительности ASP.NET.) Лучший способ решить конкретную проблему с производительностью можно найти только на основе собственного опыта. Тем не менее, эти советы должны дать вам хорошее руководство в вашем путешествии. В разработке программного обеспечения есть несколько абсолютов; каждое приложение уникально.