Смотреть что такое "аккомпанировать" в других словарях. Не кэшируйте соединение БД в объектах Application или Session

Аккомпанировать

АККОМПАНИРОВАТЬ accompagner ,> нем. akkompanieren . 1 . дипл. Приложить к чему-л., спроводить чем-л. (какую-л . посылку, отправление) . Я тот экстракт письмом своим не аккомпанировал. Кантемир Реляц. 2 172.

2. расш. Сопровождать кого-, что-л., быть дополнением к чему-л. Спинат, растение самое здоровое и для всякого желудка годное.. аккомпанирует все нарядные блюда. 1809. Гримо Прихотник 60. Однажды меня с Сазоновым (он мне всегда аккомпанирует в Ватикане) заперли. Гальберг Письма 57. Одни злословят по привычке, другие аккомпанируют. Ростопчин Ох, французы 114. Дежурный по полку ротмистр доказал, что ему хотелось есть и что аппетит у него богатырский, да и мы все аккомпанировали ему недурно, нечего сказать, не отказываясь от лафита и д"икема, которым, гостеприимный хозяин наполнял наши стаканы. В. П. Бурнашев Восп. // РА 1872 1839.

3. 1690. Лексис. муз. Сопровождать аккомпанементом. Акомпанировать своему голосу . Кн. муз. 52. Играть соло или аккомпанировать в сих концертах. Финдейз. 171. <Отец> играл на Виолончеле, и всегда акомпанировал наши Дуо. ММ 3 14. Он же Куликов фортепианами и арфою аккомпанирует. <Шарманщик> аккомпанирует вальс Ланнера свистками и трелями. Григорович Петерб. шарманщик. Он аккомпанировал Вьетану и многим певцам. Римский-Корс. Летопись. // РР 1970 1 60. || Припевать, подпевать . Но не было ли, спрашивает он, в вашем пении монотонии? Было, отвечает целомудренная супруга; но в финале все хорошо акомпанировали. Зритель 1 121. Хватайко поет и все акомпанируют: бери, большой тут нет науки. Капнист Ябеда 85.

4. перен. Сопровождая что-л., создавать определенный фон. БАС-2. Шепот продолжался, и ему аккомпанировал смущенно-счастливый смех. Мам.- Сиб. Черты из жизни Пепко. Собаки, смирно лежавшие у ворот, не выдерживали <визга поросят> и принялись аккомпанировать громким лаем и воем. А. Осипович Мечтатели. // ОЗ 1881 8 1 462. Лишь папа лесничий Дрожжинин шумно ел суточные щи, да мама для этикета аккомпанировала, едва разжимая строгие губы. Аксенов Затоварен. бочкотара. // РР 1970 3 60. - Лекс. Ян.1803: акомпанировать; Соколов 1834: акомпанирова/ть; Даль: акомпанирова/ть; САН 1933: аккомпани/ровать; Сл. 18: аккомпанировать 1734 (ако- 1792).


Исторический словарь галлицизмов русского языка. - М.: Словарное издательство ЭТС http://www.ets.ru/pg/r/dict/gall_dict.htm . Николай Иванович Епишкин [email protected] . 2010 .

Смотреть что такое "аккомпанировать" в других словарях:

    АККОМПАНИРОВАТЬ - (фр. accompagner). Сопровождать пение игрою на каком либо музыкальном инструменте. Словарь иностранных слов, вошедших в состав русского языка. Чудинов А.Н., 1910. АККОМПАНИРОВАТЬ франц. accompagner. Сопровождать пение игрою на каком либо… … Словарь иностранных слов русского языка

    аккомпанировать - См … Словарь синонимов

    аккомпанировать - и устарелое аккомпанировать … Словарь трудностей произношения и ударения в современном русском языке

    АККОМПАНИРОВАТЬ - АККОМПАНИРОВАТЬ, рую, руешь; несовер., кому. Исполнять аккомпанемент. А. на рояле. Толковый словарь Ожегова. С.И. Ожегов, Н.Ю. Шведова. 1949 1992 … Толковый словарь Ожегова

    АККОМПАНИРОВАТЬ - кого или что (сонату) чем, на чем, муз., франц. вторить, сопровождать, подголашивать, подголосить, подыгрывать; держать другой, согласный голос. Аккомпанирование ср., ·длит. аккомпанировка жен., ·об. действие по гл., вторенье, подголоска,… … Толковый словарь Даля

    аккомпанировать - (иноск. шут.) вторить, делать что в подражание другому, совместно с ним (намек на сопровождение пения или одного инструмента игрою одного или многих инструментов) Ср. Я издавна солист и аккомпанемента не ожидаю, один пью... Лесков. На ножах. 1,… … Большой толково-фразеологический словарь Михельсона

    Аккомпанировать - несов. неперех. 1. Сопровождать игрой на музыкальном инструменте или на музыкальных инструментах сольную вокальную или инструментальную партию, основную тему или мелодию музыкального произведения. 2. перен. Создавать определённый фон, сопровождая … Современный толковый словарь русского языка Ефремовой

    аккомпанировать - аккомпанировать, аккомпанирую, аккомпанируем, аккомпанируешь, аккомпанируете, аккомпанирует, аккомпанируют, аккомпанируя, аккомпанировал, аккомпанировала, аккомпанировало, аккомпанировали, аккомпанируй, аккомпанируйте, аккомпанирующий,… … Формы слов

    аккомпанировать - аккомпан ировать, рую, рует … Русский орфографический словарь

    аккомпанировать - (I), аккомпани/рую, руешь, руют … Орфографический словарь русского языка

Книги

  • Учись аккомпанировать на 6-струнной гитаре. От романсов к року и джазу , Манилов В.. В книге вы найдете необходимые сведения об аккордах, их последовательностях и способах усложнения партии ритм-гитары, о стандартной аппликатуре и типовых ритмических моделях различных жанров…

This tutorial attempts to shed some light on the subject of Threading using ASP.NET. Threading is a technique used to give the user the impression that multiple tasks are executing at the same time. The .NET Framework provides us with many types that allow us to easily and quickly add multi-threading to our .NET Web application. I’ll assume that you have some familiarity with ASP.NET and at least some experience with writing code in Visual Basic.

Through the tutorial we’ll build a pretty simple Web application that should be a good example of some basic threading concepts. Basically we’ll have 2 textboxes in which to enter a phrase, and to enter a time period in which you want the phrase to be rebuilt. Our Web threading application consists of 2 pages, one of which is the page that will start the thread, while the other is a results page that shows us the progress of our thread. The code provided should be very portable and allow you to implement your own threading application very quickly.

Before we get started…

Before we dive into the Web application, let me first give you a quick look at some of the code that you’ll be seeing.

First, we need to import the System.Threading Namespace so we can access the Thread class provided in the .NET Framework. Add this line to the top of your .aspx/.ascx file:

<%@ Import NameSpace="System.Threading" %>

Imports System.Threading

Now for demonstration purposes, here is a sample long running method. In a real life situation this method would most likely perform a task like processing a Web form, or completing a time-consuming database query.

Public Sub SomeLongMethod()

"your code that takes a while to execute

Now to execute this method and not leave our Web form hanging, we’ll start a new thread and let SomeLongMethod execute on this new thread. To do this, we have a few options. The technique I’ll use is to set up a new method that will start our new thread running. Here’s a sample thread starter function:

Public Sub SomeLongMethod_Thread()

"first, declare a new Thread, passing the constructor the address
"of SomeLongMethod. NOTE: SomeLongMethod can be replaced with your
"own method

Dim NewThread As Thread = New _
Thread(AddressOf SomeLongMethod)

"next we set the priority of our thread to lowest, setting
"the priority to a higher level can cause unexpected results.
NewThread.Priority = ThreadPriority.Lowest

"finally we start the thread executing
NewThread.Start()

And that’s it! All we have to do now is replace our call to SomeLongMethod with a call to SomeLongMethod_Thread , and the long method will execute on its own thread. Normally, we would redirect the user to the results page at the end of the SomeLongMethod_Thread method. However in this example I left that out to prevent confusion — I’ll demonstrate it in the following example, which illustrates the use of Threading in an ASP.NET Web application.

Using Threading to Rebuild a String

The first file we’ll look at is default.aspx. This will be the page where we’ll get 2 values from the user, and start a new thread. The second file we’ll look at is the results page, where we’ll poll the Session variables created in the thread, and display current thread stats to our user. I’ll go through default.aspx method-by-method, and then do the same for the results.aspx page. The source code for this file is available at the end of this tutorial.

NOTE: I’ve assumed that your Web server has Session variables enabled. If you have Session variables Disabled, or you have cookies disabled on your browser, the results of the following example will not display correctly.

A Simple Example (default.aspx)

Let’s begin by looking at the Page_Load function for default.aspx

Sub Page_Load(ByVal sender As System.Object, ByVal e
As System.EventArgs)

SyncLock Session.SyncRoot
"here, we initialize 3 session variables to hold our results
Session("Complete") = False
Session("Status") = ""
Session("Phrase") = ""
End SyncLock
d Sub

In this method we simply initialize 3 session variables that we’ll use in our next few methods. Session("Complete") will be the sentinel for our results page. When the thread is complete we will set Session("Complete") to True . The Session("Phrase") variable will be what we use to hold our partial phrase as we slowly build it. Session("Status") is just a variable to hold the start time and the end time. Now let’s look at our phrase re-building method:

Sub PhraseBuilder()

Dim str As String = ""
Dim i As Integer = 0

Dim startTimeTicks As Long = 0
Dim strStartTime As String = ""

Dim totalSleepTime As Double = 0.0

"log our start time, in ticks, and in Long Date format
startTimeTicks = DateTime.Now.Ticks
strStartTime = "Thread Started: " & DateTime.Now

" get phrase
str = txtPhrase.Text

"convert users time from seconds to milliseconds
totalSleepTime = 1000.0
totalSleepTime = totalSleepTime * CInt(txtTotalThreadLife.Text)
totalSleepTime = (totalSleepTime / str.Length)

For i = 0 To str.Length - 1

"this method will put our thread to sleep for the specified
"number of milliseconds. without the sleep, this method would
"execute too fast to see the thread working.
Thread.Sleep(totalSleepTime)

"we use synclock to block any other thread from accessing
"session variables while we are changing their values.
SyncLock Session.SyncRoot

Session("Status") = "Thread is " & _
Format((i / (str.Length - 1)) * 100, "#0.00") & _
"% complete." & " - Time Elapsed: " & _
Format((DateTime.Now.Ticks - startTimeTicks) / 10000000 _
, "#0.00") & " sec. Target: " & txtTotalThreadLife.Text & _
".00 sec."

SyncLock Session.SyncRoot
"rebuild phrase 1 letter at a time
Session("Phrase") &= str.Chars(i).ToString
End SyncLock

"our method is complete, so set the Session variables
"accordingly
SyncLock Session.SyncRoot
Session("Status") = strStartTime & _
"
Thread Complete. End Time: " & DateTime.Now & "
"

Session("Complete") = True
End SyncLock

Ok, now let’s dissect this method a little. Basically what we’re doing here is forcing a method that would otherwise run quickly to run on a schedule based on user input. This is done using the Thread.Sleep(ByVal millisecond as Integer) method. This method allows us to put the thread to sleep for the specified number of milliseconds. This Sleep method can be used in any method, not just one that’s executing on a new thread.

The other interesting technique we utilize is the use of the Synclock method. Synclock is used to block other threads from trying to obtain the same Synclock . To protect the variables from simultaneous access, we need to obtain the same Synclock before we access the variables everywhere else in the code. This is a necessity in a multi-threaded Web application to ensure that two methods aren’t reading/writing to the same variable at the same time. The Synclock method is identical to using the Monitor.Enter(Me) method that’s also provided in the System.Threading Namespace .

There are only two methods left to go! The next method we’ll look at is the PhraseBuilder_Thread function. This function is almost identical to the example at the beginning of the article:

Sub PhraseBuilder_Thread()

"method to start our phrase builder method executing
"on a new thread.

Dim myThread As Thread = New Thread(AddressOf PhraseBuilder)

MyThread.Priority = ThreadPriority.Lowest

"//start the new thread
myThread.Start()

"now redirect to the results page
Response.Redirect("results.aspx")

Now all that’s left is to call our PhraseBuilder_Thread method when the user clicks the submit button. Here’s the short code:

Sub btnSubmit_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs)

"start PhraseBuilder thread...
PhraseBuilder_Thread()
End Sub

A Simple Example(results.aspx)

Now we’ll take a look at the results page. Basically our results page will check the status of the Session("completed") variable on the Page_Load , and react accordingly. Here’s the Page_load function for results.aspx:

Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
"Put user code to initialize the page here
"check the value of Session("Completed"), if it is True, stop writing

If Session("Complete") <> True Then

"make sure session variables are enabled, if not warn user

If Session("Complete") <> False Then
"error with session variable, Session("Complete") is not
"True or False
lblComplete.Text = "Error with Session("Complete")"

"set page to auto refresh page every 2 seconds, until thread is done

Response.Write("")

SyncLock Session.SyncRoot
lblStatus.Text = Session("Status") & "
Processing. . ."

End SyncLock

Else
"thread is complete, stop writing refresh tag, and display
"results
SyncLock Session.SyncRoot
lblStatus.Text = Session("Status")
lblPhrase.Text = Session("Phrase")
lblComplete.Text = Session("Complete")
End SyncLock

This Page_Load function checks the status of the Session("Complete") variable and reacts accordingly. Feel free to customize you results page to suit you needs, but I recommend checking for the case when the Session("Completed") variable is not set to True, or False. This usually happens when Session variables are disabled, or you have cookies disabled. Also, you can remove the Response.Write statement if you don’t want the page to automatically refresh.

In Conclusion

Well that’s all there is to it! Hopefully you have just written your first ASP.NET application using threading.

Для ресайзинга картинок вы можете использовать готовое решение – imageresizing.net. Оно выполнено в виде HTTP Module для ASP.NET и производит ресайзинг картинок "на лету". То есть во время загрузки картинки производится только ее загрузка, без трансформаций. Ресайзинг же производится тогда, когда запрашивается специфичный размер самой картинки и выполняется асинхронно, поскольку страница уже отображается у пользователя. Также используется кэш, чтобы избежать постоянной регенерации картинок.

Но так как вопрос был про "многопоточность asp.net", то поделюсь соображениями еще и по этой теме. Сразу скажу, что есть готовое решение – HangFire , но также интересны и причины его появления.

В ASP.NET каждый запрос выполняется внутри отдельного потока. Так как создание потока является достаточно "дорогой" операцией, то для каждого запроса отдается "в аренду" готовый поток из пула потоков.

В интернете ходит множество слухов, что долгоиграющие запросы ASP.NET могут "забить" все потоки из пула, и новые запросы будут нещадно попадать в request queue и ожидать своей очереди на исполнение. Такая ситуация называется Thread pool starvation (или thread pool contention) и приводит к снижению пропускной способности сервера при увеличении количества запросов.

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

В ASP.NET в общем и в ASP.NET MVC в частности есть понятие асинхронной обработки запросов. В MVC 3 был AsyncController, начиная с MVC 4 и C# 5.0 была введена поддержка async-методов . Однако в этой программной модели запрос должен ждать завершения всех асинхронных операций, и в вашем случае получится, что вы отдаете ресайз картинки на выполнение в другом потоке, и ожидаете его завершение в потоке, который исполняет запрос. В этом случае вы ничего не выигрываете, и даже проигрываете, потому что вместо одного потока на обработку запроса начинает выделяться два потока.

В ASP.NET приложении вы также можете либо создать поток самостоятельно (что плохо, потому что это дорогая операция), либо использовать некоторый пул предварительно инициированных потоков самостоятельно, либо использовать тот же самый Thread Pool (посредством Task-based API либо ThreadPool.QueueUserWorkItem) и не ожидать его завершения, при этом ресайз картинки будет происходить вне пределов контекста обработки запроса. В этом случае пользователю не нужно будет ожидать завершения долгой операции, но здесь может возникнуть следующая проблема.

Если в качестве веб-сервера выступает IIS (что скорее всего так, пока Owin не пошел в массы), то ваше приложение хостится в одном или нескольких рабочих процессах IIS, которые работают под управлением пула приложения. А пул приложения имеет множество всевозможных настроек, которые могут привести к recycling"у приложения . Это хороший процесс, который экономит ресурсы сервера, особенно на shared хостингах. Вот только у него есть таймаут на его завершение, который по-умолчанию равен 90 секундам.

Когда application pool начинает процесс ресайклинга, он отсылает ASP.NET приложению команду на остановку (shutdown). При этом само ASP.NET приложение перестает принимать новые запросы, и ждет завершения текущих с собственным дефолтным таймаутом (ShutdownTimeout в конфиге application pool) в 30 секунд. Если текущие запросы успевают выполниться за отведенное время, то сразу после этого происходит выгрузка домена приложения.

Вот тут и кроется первая проблема – ASP.NET по-умолчанию просто не обращает внимания на все ваши фоновые потоки, как созданные собственноручно, так и потоки из Thread Pool. И если после завершения обработки текущих запросов ваша фоновая задача не была завершена – это ваши проблемы, она будет просто прервана исключением ThreadAbortException. И если не были предприняты конкретные шаги по ее перезапуску, то сами потом будете объяснять пользователям, почему иногда картинки или отчеты до них так и не доходят. Конечно же, вероятность вроде бы небольшая, но запросов много, причин у recycling"а много, да и время жизни проекта тоже большое. А бороться с последствиями довольно неприятно.

Еще в ASP.NET есть интерфейс IRegisteredObject и методы HostEnvironment.RegisterObject и HosterEnvironment.UnregisterObject (а вот и ), которые уведомляют ASP.NET о том, что есть операция, завершения которой нужно ожидать при получения события об остановке приложения. Правда вот ShutdownTimeout при этом никуда не девается, а гарантировать, что все фоновые задачи будут завершены за 30 секунд очень сложно.

Так что основная проблема – это вероятность прерывания потока, выполняющего задачу из-за таймаутов. Я лично ловил несколько раз такие исключения, и разрешение последствий иногда было довольно неприятной штукой. Увеличивать же таймауты не совсем разумно, поскольку именно они помогают приложению сохранять хоть какую-то стабильность, когда возникают гораздо большие проблемы по совершенно другим причинам.

В этой ситуации 100% работающее решение – написать собственное приложение, которое будет "крутиться" постоянно и оформить его в виде службы Windows. Она будет перезапускаться гораздо реже, и таймауты можно настроить так, как душе угодно. Однако в добавок нужно еще организовать протокол общения (тут можно взять, конечно WCF), и разработать грамотную модель обработки задач. Но и первоначальная разработка, и последующее тестирование несколько сложно. А оправдать такое монстроидальное решение тем, что "нам нужна гарантия при ресайзе картинок" бывает тоже довольно трудно.

Самым обидным для меня было то, что для Ruby on Rails было полно всяких решения, которые решали подобную проблему с long-running процессами на стороне веб-сервера на общий манер: Resque , Sidekiq , delayed_job и иже с ними. Для платформы.NET есть несколько разработок на NuGet, но они пока еще слишком слабые, и иногда не дают гарантий того, что задача будет выполнена всегда после ее создания.

Подождав год-другой, я решил все-таки сделать подобный общий инструмент для.NET – HangFire . На данный момент у него версия 0.7, что означает его неполную готовность для массового использования, однако он гораздо стабильнее и функциональнее, чем большинство собственных разработок. Плюс, он сейчас находится в активной разработке. Схема и публичное API довольно стабильно, и оно уже используется в нашей системе, которая находится в продакшене. Так что можете попробовать, а если возникнут вопросы – то смело создавайте тикет на гитхабе.

Производительность — это особенность приложения. Вам нужно думать о производительности сразу при проектировании приложения, иначе вы будете переписывать ваш исходный код позже.

Публикуемый ниже материал представляет собой первый совет из целой серии советов по оптимизации приложений, использующих технологии ASP и Visual Basic Scripting Edition (VBScript). Большинство из них были многократно обсуждены и c успехом проверены на веб-сайте Microsoft Corporation и других ASP-сайтах. Авторы материала подразумевают, что вы уже знакомы с основами разработки ASP-приложений, включая VBScript и/или JScript, ASP-сессиями и др. важными объектами (Request, Response и Server).

Кэшируйте часто используемые данные на сервере

Типичная ASP-страница получает данные из базы данных и затем выводит их в формате HTML. Независимо от скорости вашей базы данных, получение данных из памяти сервера намного быстрее, чем обработка sql-запроса к конечной базе данных. Получение данных, сохраненных на локальном жестком диске, также обычно быстрее, чем получение информации из БД. Поэтому одним из основных путей увеличения скорости работы вашей ASP-страницы является кэширование часто используемой информации в памяти или на жестком диске.

Кэширование данных — это классический компромисс «место или время». Если вы избрали для кэширования правильный материал, вы можете видеть внушительное повышение производительности вашего приложения. Чтобы кэширование было эффективным нужно использовать для временного хранения только те данные, которые многократно используются для вывода и каждый раз трудоемки для повторных вычислений. Кэш, полный устаревшей информации, будет пустой тратой памяти сервера.

Данные, которые не изменяются часто, являются хорошим кандидатом для кэширования, потому что вам не надо будет волноваться относительно их синхронизации через какое-то время с конечной базой данных. Выпадающие списки (сombo-box), таблицы ссылок, пункты меню, и переменные конфигурации сайта (включая имена DSN, адреса IP и URL) — первые кандидаты для хранения в кэше. Заметьте, что вы можете кэшировать представление данных много быстрее, нежели данные сами себя. Если ASP-страница изменяется не так часто и ее временный кэш будет весьма внушительным (например, полный каталог изделий фирмы), попробуйте использовать сгенерированные HTML-страницы, чем каждый раз загружать сервер генерацией ASP-страниц.

Кэшируйте часто используемые данные в объектах Application или Session

Объекты Application и Session служат для хранения данных в памяти, значения которых могут быть доступны между несколькими HTTP-запросами (в отличие от обычных переменных, чьи значения доступны только в теле одной ASP-страницы). Данные объекта Session доступны только одному пользователю (в течении его сессии), в то время как данные Application доступны всем пользователям веб-сайта. Поэтому часто перед разработчиком возникает вопрос: в каком из объектов сохранять часто используемые данные. Обычно, для инициализации переменных этих объектов используются процедуры файла Global.asa — Application_OnStart() или Session_OnStart() соответственно. Если в вашем Global.asa еще нет этих процедур, то вы можете добавить их сами или инициализировать переменные, когда это будет необходимо. Примером может быть следующая процедура, использующая Application для хранения значений многократно использующейся переменной EmploymentStatusList. Процедура проверяет существование данных в EmploymentStatusList и при необходимости расчитывает их заново:

<% Function GetEmploymentStatusList Dim d d = Application("EmploymentStatusList") If d = "" Then " Если значения нет - выполним расчет d = FetchEmploymentStatusList() Application("EmploymentStatusList") = d End If GetEmploymentStatusList = d End Function %>

Подобную функцию можно написать для любой задачи, где не стоит каждый раз заново выполнять тродоемкий расчет. При этом могут быть сохранены данные любого формата (тип variant). Например, вы можете использовать строковые значения, целые числа, массивы или набор записей. Например:

Function FetchEmploymentStatusList Dim rs Set rs = CreateObject("ADODB.Recordset") rs.Open "select StatusName, StatusID from EmployeeStatus", _ "dsn=employees;uid=sa;pwd=;" "Получить все строки FetchEmploymentStatusList = rs.GetRows() rs.Close Set rs = Nothing End Function

Если полученный массив будет часто использоваться, тогда лучше хранить его сразу в виде HTML-списка, чем массив, которое каждый раз нужно преобразовывать в HTML:

Function FetchEmploymentStatusList Dim rs, fldName, s Set rs = CreateObject("ADODB.Recordset") rs.Open "select StatusName, StatusID from EmployeeStatus", _ "dsn=employees;uid=sa;pwd=;" s = "" & vbCrLf rs.Close Set rs = Nothing FetchEmploymentStatusList = s End Function

Кэшируйте данные на диске веб-сервера

Иногда в памяти вашего веб-сервера может быть слишком большое количество данных. "Слишком много", конечно, является спорным вопросом — это зависит от того, сколько памяти вы хотите использовать, а также число элементов для кэширования и частота, с которой эти элементы будут запрашиваться. В любом случае, если вы имеете слишком большое количество данных для кэширования в памяти, подумайте о переносе кэша в текстовый или XML-файл на жесткий диск веб-сервера. Вы можете одновременно комбинировать кэширование на диске и в памяти, чтобы сформировать оптимальную стратегию для вашего сайта.

Заметьте, что при измерении производительности одиночной ASP-страницы, получение данных с диска может не всегда быть быстрее, чем получение равноценных данных из БД. Но "файловое" кэширование уменьшает загрузку БД и сети, а при высокой загрузке БД до, значительно улучшит общую производительность после. Кэширование может быть очень эффективно при кэшировании результатов сложных запросов (например, соединение таблиц), трудоемких процедур сохранения, больших наборов записей. Чтобы убедится, насколько выгодным будет это решение требуется протестировать различные схемы сохранения.

ASP и COM обеспечивают несколько инструментальных средств для создания схем кэширования на диске. Функции набора записей ADO Save() и Open() сохраняют и загружают recordset c диска. Используя эти методы вы можете переписать код из прошлого совета, заменяя запись в объект Application на метод Save() для записи в файл.

Есть несколько других компонентов, которые работают с файлами:

* Scripting.FileSystemObject позволяет создавать, читать и записывать файл.
* MSXML, MicrosoftR XML parser поддерживает сохранение и загрузку XML-документов.
* Объект LookupTable (например, используемый на MSN.com) — лучший выбор для загрузки простых списков с диска.

Наконец, рассмотрите вопрос принудительного кэширования информации на диске. Сгенерированный HTML-код может быть сохранен на диске как.htm или.asp файл; гиперссылки могут указывать прямо на этот файл. Вы можете автоматизировать процесс генерации HTML, используя коммерческие инструментальные средства типа XBuilder или средства публикации в Интернет, входящие в MicrosoftR SQL ServerT. Кроме того, при помощи директивы #include можно включать отдельные HTML-части в файл ASP или читать HTML-файл с диска используя FileSystemObject. Например, на начальной странице vbCode (http://vbcity.com/vbcode/ru/home.asp) приводятся 10 последних тем обсуждения двух дискуссионных форумов. Отобразить эти списки можно при помощи создания двух наборов записей ADO при каждом обращении к данной странице или, следуя данному совету, сохранить их однажды в виде HTML-файла list.inc, а затем включать в home.asp:

Второй путь работает значительно быстрее.

Избегайте кэшировать медленные компоненты в объектах Application или Session

Несмотря на то, что кэшированиe данных в объектах Application или Session может быть хорошей идеей, кэширование COM-объектов может иметь серьезные ловушки. Занесение наиболее используемых COM-объектов в объекты Application или Session часто соблазняет, но, к сожалению, много COM-объектов, включая все, написанные в Visual Basic 6.0 или ранее, могут вызывать серьезные критические проблемы после сохранения в объектах Application или Session.

В частности, любой компонент, который выполняется медленно, вызовет критические проблемы когда кэшируется в объектах Session или Application. Быстрый (проворный non-agile) компонент — компонент, помеченный ThreadingModel=Both, который объединен Free-threaded marshaler (FTM), или — компонент, помеченный ThreadingModel=Neutral. (Neutral — новая модель в WindowsR 2000 and COM+). Следующие компоненты не проворны:

* Free-threaded components.
* Apartment-threaded components.
* Single-threaded component.
* Configured components (библиотека Microsoft Transaction Server (MTS)/COM+ и серверные приложения) не проворны пока они Neutral-threaded. Apartment-threaded components и другие не проворные компоненты хорошо работают в пределах страницы (т.е. создаются и разрушаются в пределах одной ASP-страницы).

В IIS 4.0 компонент, отмеченный ThreadingModel=Both выполняется быстро. В IIS 5.0 уже не так достаточно. Компонент не должен только быть отмечен как Both, он должен также объединен FTM.

IIS выполняет проверку компонентов, но если вы хотите ее отменить (т.е. хотите позволить непроворным компонентам быть сохраненными в объектах Application или Session), вы можете установить AspTrackThreadingModel в metabase в значение True. Но это (изменение AspTrackThreadingModel) не рекомендуется.

IIS 5.0 выдаст сообщение об ошибке, если Вы пытаетесь сохранить непроворный компонент, созданный с использованием Server.CreateObject, в объекте Application. Вы можете обойти это, используя в Global.asa, но это также не рекомендуется, поскольку это ведет к проблемам (очереди и сериализация), объясняемым ниже.

Что же все-таки неправильно если вы кэшируете непроворные компоненты? Непроворный компонент, кэшируемый в объекте Session блокирует Session от других рабочих потоков (thread) ASP. ASP обслуживает пул (контейнер) рабочих потоков, запрашиваемых другими сервисами. Обычно, новый запрос обрабатывается первым доступным потоком. Если Session блокирована, то запрос должен ждать поток, когда он станет доступным. Проведем аналогию, которая поможет понять эту ситуацию: вы идете в магазин, выбираете несколько булок, и платите за них в кассе #3. Всякий раз, после того как вы выбрали булки в том магазине, вы всегда оплачиваете их в кассе #3, даже в том случае, когда в других кассах короче очередь или даже вообще нет покупателей.

Сохранение непроворных компонентов в объект Application накладывает столь же негативный эффект на производительность. ASP создает специальный поток для выполнения меделенных компонентов в пределах Application. Это имеет два последствия: все запросы выстраиваются в очередь к этому потоку и все запросы сериализуются. Выстраивание в очередь означает, что параметры были сохранены в общедоступной области памяти; запросы переключаются к специальному потоку; метод компонента выполнен; результаты выстраиваются в общедоступную область. Сериализация (преобразование в последовательную форму) означает, что все методы выполняются в одно время. Для двух различных потоков ASP не возможно одновременное выполнение методов общедоступного компонента. Это уничтожает многопотоковость (параллелизм), особенно на мультипроцессорных системах. Хуже всего то, что все непроворные компоненты в пределах Application совместно используют один поток ("Host STA"), так что негативные результаты сериализации налицо.

Смущены? Есть некоторые общие правила. Если Вы пишете объекты в Visual Basic (6.0 или ранее), не храните их в объектах Application или Session. Если вы не знаете потоковую модель объекта, не храните его в кэше. Вместо кэширования где-либо непроворных объектов, вы должны создать и удалить их на каждой странице. Объекты выполнятся непосредственно в рабочем потоке ASP и не будет никакой очереди или сериализации. Производимость будет адекватна, если COM-объекты запущены под IIS и если они не используют много времени, чтобы инициализироваться и уничтожаться. Заметьте, что однопотоковые (single-threaded) объекты не должны использоваться этот путь. Будьте внимательным — VB может создавать однопотоковые объекты! Если вы используете однопотоковые объекты, этот путь (типа таблицы Microsoft Excel) не рассчитывает на высокую производительность.

Наборы записей (recordset) ADO могут безопасно кэшироваться когда ADO отмечен как Free-threaded. Чтобы сделать ADO как Free-threaded используйте файл Makfre15.bat, который обычно зафиксирован в каталоге Program FilesCommon FilesSystemADO.

Предупреждение: ADO не должен быть Free-threaded, если вы используете Microsoft Access в качестве БД. Набор записей ADO должен быть также вообще отсоединен, если вы не можете управлять конфигурацией ADO на вашем веб-сайте.

Не кэшируйте соединение БД в объектах Application или Session

Кэширование соединений ADO — обычно плохая стратегия. Если один объект Connection сохранен в объекте Application и используется на всех страницах, то все страницы будут бороться за использование этого соединения. Если объект Connection сохранен в ASP-объекте Session, то соединение БД будет создано для каждого пользователя. Это создает излишнюю загрузку веб-сервера и БД.

Вместо кэширования соединений БД, создавайте и уничтожайте объекты ADO на каждой ASP странице, которая использует ADO. Это эффективно, потому что IIS имеет встроенное подключение БД. Более точно, IIS автоматически допускает объединение подключений OLEDB и ODBC. Это гарантирует, что создание и уничтожение связей на каждой странице будут эффективны.

Так как соединенные наборы хранят ссылки на подключение БД, это следует, что вы должны не кэшировать соединенные наборы в объектах Application или Session. Однако, вы можете безопасно кэшировать отсоединенные наборы, которые не держат ссылку на подключение. Чтобы отсоединить набор записей, сделайте следующие два шага:

Set rs = Server.CreateObject("ADODB.RecordSet") rs.CursorLocation = adUseClient " шаг 1 " Заполните recordset с данными rs.Open strQuery, strProv " Теперь отсоедините recordset от источника данных rs.ActiveConnection = Nothing " шаг 2

Подробную информацию относительно подключений смотрите в справочниках по ADO и SQL Server.

Разумное использование объекта Session

Теперь, когда в предыдущих советах были раскрыты достоинства кэширования данных в объектах Applications и Sessions, мы собираемся предложить вам избегать использования объекта Session. Сессии имеют несколько ловушек когда используются на загруженных сайтах. Под "загруженными" имеются ввиду сайты с сотнями запрашиваемых страниц в секунду или тысячами пользователей одновременно. Этот совет также важен для сайтов, которые должны масштабироваться горизонтально — т.е. те сайты, которые используют несколько серверов для распределения нагрузки и обеспечения отказоустойчивости при сбоях. Для меньших сайтов, типа intranet-сайтов, преимущества применения Sessions все же перевешивают.

Обобщая, ASP автоматически создает Session для каждого пользователя, который обращается к веб-серверу. Каждая сессия занимает приблизительно 10 Кб памяти (сверх любых данных, сохраненных в Session) и немного замедляет выполнение всех запросов. Сессия остается действующей до окончания таймаута (timeout), обычно 20 мин.

Но самая большая проблема при использовании сессий — это не производительность, а расширяемость. Сессии не охватывают все задействованные веб-сервера; как только Session была создана на одном сервере ее данные остаются там. Это означает, что если вы используете сессии на мультисерверном веб-сайте, вы должны придумать стратегию для обработки запросов каждого пользователя, которые должны быть всегда направлены на сервер, на котором существует сессия этого пользователя. Это называется "застреванием" пользователя на сервере (или "липкой сессией").

Объект Application также не охватывает все сервера: если вам нужно совместно использовать и обновлять данные Application через веб-сервера, вам нужно использовать конечную базу данных. Однако неизменяемые (read-only) данные Application все же полезны на мультисерверных сайтах.

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

Если же вы не используете Session, то убедитесь, что отключили их. Это можно сделать посредством Internet Services Manager (см. документацию по ISM). Но если вам все-таки необходимо использовать сессии, то есть несколько путей уменьшить их удары про производительности.

Вы можете переместить содержимое, которое не требует сессий (например, страницы help и т.д.) в отдельное ASP-приложение, у которого сессии выключены. Кроме того, на страницах, где объект Session не используется, применяйте следующую директиву, помещещаемую вверху страницы:

<% @EnableSessionState=False %>

Одна из основных причин ее применения — то, что Session создает интересную проблему в случае использования фрэймов (frameset). ASP гарантирует, что в любое время будет выполняться только один запрос от Session. Это делается для того, чтобы при одновременном запросе одним пользователем нескольких страниц, только один ASP-запрос был обработан сессией, что помогает избежать проблем многопоточного доступа к объекту Session. К сожалению, в результате этого все страницы в frameset будут загружаться последовательно, а не одновременно, и пользователю придется продолжительное время ждать полной загрузки. Мораль этой истории: если вы не уверены, что с использованием фрэймов и Session ваше приложение правильно работает, то используйте:

<% @EnableSessionState=False %>

Альтернативой использованию объекта Session являются многочисленные параметры управления Session. При передаче малых объемов данных (менее 4 Кб) обычно рекомендуется использовать Cookies, переменные QueryString и скрытые (hidden) переменные форм. При использовании большого количества передаваемых параметров (например, корзина произведенных заказов в он-лайн магазине) наиболее лучший выбор — конечная база данных.

Статья будет полезна как новичкам, так и профессионалам. Первые получат сведения об основных возможностях MySQL, без чтения документации. А уже имея представление о…

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

  1. Необработанное исключение в потоке, несвязанном с запросом, может снять процесс.
  2. Если запустить сайт в веб-ферме, то есть вероятность случайно завершить несколько экземпляров приложения, которое могло запустить несколько экземпляров одной и той же задачи одновременно.
  3. Домен приложения, в котором запущен сайт, по разным причинам может выгрузиться и снять фоновую задачу, запущенную в нем.
Конечно, можно написать собственный менеджер для управления фоновыми задачами. Но, вероятнее всего, Вы сделаете это неправильно. Никто не собирается оспаривать Ваши навыки разработчика. Просто создание подобного менеджера - это достаточно тонкая вещь. Да и зачем Вам это надо?

Есть множество отличных вариантов запуска задач в фоновом режиме. И не просто абстрактных методик, а готовых библиотек.

Какие-то ASP.NET приложения могут работать на Ваших собственных серверах под IIS, какие-то размещаться в Azure.

Для запуска фоновых задач можно выделить несколько вариантов:

HANGFIRE

И последний в обзоре, но, безусловно, непоследний по функциональности, наиболее продвинутый из всех Hangfire. Это действительно очень продвинутый фреймворк для фоновых задач в ASP.NET. Опционально он может использовать Redis, SQL Server, SQL Azure, MSMQ или RabbitMQ для повышения надежности выполнения задач.

Документация Hangfire действительно превосходна. Хотелось бы, чтобы каждый проект с открытым исходным кодом имел такую документацию.

Одной из самых эффектных функций Hangfire является встроенная аналитическая панель, которая позволяет просматривать расписания, выполняющиеся задания, успешные и неуспешно завершенные задания.

Hangfire позволяет легко определить задачи типа «запустить и забыть», информация о которых будет храниться в базе данных:

BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget"));
Можно отсрочить выполнение задачи:

BackgroundJob.Schedule(() => Console.WriteLine("Delayed"), TimeSpan.FromDays(1));
Или запустить задачу в CRON стиле

RecurringJob.AddOrUpdate(() => Console.Write("Recurring"), Cron.Daily);
Работать с Hangfire очень удобно. Hangfire имеет хорошую документацию и обучающие руководства , основанные на реальных примерах.

Hangfire - это целая экосистема для работы с фоновыми задачами в ASP.NET приложениях.

Библиотеки доступны в виде открытых исходных кодов или Nuget пакетов.

Итоги (лично от себя)

Выбирая библиотеку для себя, я, с одной стороны, хочу иметь приличную функциональность, а с другой, пока не хочу использовать, например, базу данных для хранения информации о запущенных задачах. Поэтому простые решения типа WebBackgrounder или QueueBackgroundWorkItem я даже не стал рассматривать.

Я уже знаю, что мне нужно запускать больше одного процесса, и работать процессы могут долго (ограничение в 90 секунд на завершение в QueueBackgroundWorkItem). FluentScheduler выглядит неплохо, но хотелось большего. Hangfire – отличное решение, но, вроде, сразу требует использования базы данных для хранения очереди задач. Да и не совсем там все бесплатно – есть и платная версия.

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

Если вы знаете другие библиотеки для запуска фоновых задач или имеете опыт решения подобных задач – делитесь в комментариях.