Обработка на сервере с индикатором (упр. приложение)

Публикация № 76309

Программирование - Работа с интерфейсом

77
Обработка на сервере с отображением процесса загрузки и возможностью прерывания

&НаСервере
Функция ИнициализацияОбработкиСервер()

   
Запрос = Новый Запрос;
   
Запрос.Текст =
   
"ВЫБРАТЬ
    |   Спр.Ссылка
    |ИЗ
    |   Справочник.Банки КАК Спр"
;

   
Данные      = Запрос.Выполнить().Выгрузить();
   
АдресДанных = ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);

 
  // Обработка
    // В справочнике ~ 4000 элементов

    Возврат Данные.Количество();

КонецФункции

&НаСервереБезКонтекста
Функция ОбработатьЭлемент(ДанныеЭлемента)

   
СпрОбъект = ДанныеЭлемента.Ссылка.ПолучитьОбъект();

   
// Обработка

   
СпрОбъект.ОбменДанными.Загрузка = Истина;
   
СпрОбъект.Записать();

КонецФункции

&НаСервереБезКонтекста
Функция ОбработатьПорциюНаСервере(Начало, Конец, АдресДанных)

   
Данные = ПолучитьИзВременногоХранилища(АдресДанных);

    Для
Счетчик = Начало - 1 По Конец - 1 Цикл

       
ОбработатьЭлемент(Данные[Счетчик]);

    КонецЦикла;

КонецФункции

&НаКлиенте
Процедура ВыполнитьОбработку(Команда)

   
Количество      = ИнициализацияОбработкиСервер();
   
РазмерШага      = 10;
   
КоличествоШагов = Цел(Количество / РазмерШага);
   
КоличествоЦел   = КоличествоШагов * РазмерШага;

    Если
КоличествоЦел < Количество Тогда
       
Элементы.Индикатор.МаксимальноеЗначение = КоличествоШагов + 1;
    Иначе
       
Элементы.Индикатор.МаксимальноеЗначение = КоличествоШагов;
    КонецЕсли;

    Для
Счетчик = 1 По КоличествоШагов Цикл

       
ОбработатьПорциюНаСервере(РазмерШага * (Счетчик - 1) + 1, РазмерШага * Счетчик, АдресДанных);
       
Индикатор = Счетчик;
       
ОбработкаПрерыванияПользователя();
       
ОбновитьОтображениеДанных();

    КонецЦикла;

    Если
КоличествоЦел < Количество Тогда

       
ОбработатьПорциюНаСервере(КоличествоШагов * РазмерШага + 1, Количество, АдресДанных);
       
Индикатор = Индикатор + 1;

    КонецЕсли;

КонецПроцедуры

77

Скачать файлы

Наименование Файл Версия Размер
ОбработкаНаСервереСИндикатором83.epf
.epf 7,84Kb
05.04.16
118
.epf 7,84Kb 118 Скачать
ОбработкаНаСервереСИндикатором.epf
.epf 7,26Kb
05.04.16
318
.epf 7,26Kb 318 Скачать

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. acsent 1135 30.09.10 17:44 Сейчас в теме
Думал, что самая затратная прцедура будет
Данные = ПолучитьИзВременногоХранилища(АдресДанных);

а оказалось, вызов сервера куда более затратен
2. Evg-Lylyk 2547 01.10.10 17:18 Сейчас в теме
Приблизительно о том же писал здесь http://infostart.ru/public/71407/
3. acsent 1135 01.10.10 17:22 Сейчас в теме
Основная фишка в том, чтобы получить выборку данных на сервере и не передавать ее на клиент
4. Evg-Lylyk 2547 01.10.10 18:00 Сейчас в теме
(3) Согласен это важно. Разумно осуществлять индикацию раз в секунду тогда будет меньше вызовов сервера... упростится код
5. Mopo3 289 07.06.11 19:02 Сейчас в теме
Имх лучше из клиента вызывать обработчик ожидания каждую секунду, который читает из временного хранилища счетчик итераций обработки. Счетчик итераций во временном хранилище обновляет сам обработчик данных. Зная общее количество состояние вывести просто.
dj_serega; f.lex; Krio2; leonidol; yandextesting; ll13; +6 1 Ответить
9. KillerMann 166 12.02.14 12:14 Сейчас в теме
(5) Mopo3, идея у автора хорошая. А вот Вашу не поддерживаю. Каким образом отработает обработчик ожидания на клиенте если на серверной части будет крутиться процедура(функция) обработки результата запроса? Если знаете решение, то пример в студию, только заведомо рабочий. А пока минус за ответ, т.к. считаю ответ вводящий в заблуждение.
evseevoleg; +1 Ответить
10. acsent 1135 12.02.14 12:23 Сейчас в теме
(5) Чтоб подключить обработчик нужно запускать фоновое задание. А чтоб его запускать нужно изменять конфигурацию
11. KillerMann 166 12.02.14 12:49 Сейчас в теме
(10) на сколько я понял Mopo3 имел ввиду ПодключитьОбработчикОжидания() в модуле формы, а обработка ожидания не отработает пока не выполнится процедура(функция) на сервере. Или я чего-то не знаю? Речь та не шла за регламентные задания. Если есть решение для не типовой конфигурации и так чтобы можно было воспользоваться методом ПодключитьОбработчикОжидания(), то прошу поподробней описать, в жизни пригодится.
14. doom2good 5 10.11.15 11:55 Сейчас в теме
(5) Mopo3,
Не подскажете, как реализовать через ПодключитьОбработчикОжидания()?
в моем варианте
Процедура ВыполнитьОбработку(Команда)
	
	ПодготовитьДанныеСервер();
	МаксимальноеЗначение = КоличествоДанныхВХранилище();
	
	ПодключитьОбработчикОжидания("ОбновитьСтатус", 1);
	ПодключитьОбработчикОжидания("ОбработатьДокументы", 1, Истина);

КонецПроцедуры
Показать


&НаКлиенте
Процедура ОбновитьСтатус()

	ОстатокЭлементов = КоличествоДанныхВХранилище();
	ВсегоЭлементов = МаксимальноеЗначение;
	
	Состояние("Обработка документов", 100 - ОстатокЭлементов /(ВсегоЭлементов/100), "Документы обрабатываются...");
	
	Если ОстатокЭлементов = 0 Тогда
	
		ОтключитьОбработчикОжидания("ОбновитьСтатус");
		Предупреждение("Обработка завершена!");
	
	КонецЕсли;

КонецПроцедуры
Показать


&НаКлиенте
Процедура ОбработатьДокументы()

	ОбработатьДокументыСервер(АдресХранилищаДанных, АдресХранилищаКоличества);

КонецПроцедуры

&НаСервереБезКонтекста
Процедура ОбработатьДокументыСервер(АдресХранилищаДанных, АдресХранилищаКоличества)

	НепроведенныеДокументы = ПолучитьИзВременногоХранилища(АдресХранилищаДанных);
	
	ВсегоДокументов = НепроведенныеДокументы.Количество();
	
	Для Каждого цДокумент Из НепроведенныеДокументы Цикл
		
		обработатьДокумент(цДокумент);
		
		ВсегоДокументов = ВсегоДокументов - 1;
		ПоместитьВоВременноеХранилище(ВсегоДокументов, АдресХранилищаКоличества);
		
	КонецЦикла;

КонецПроцедуры
Показать


В этом случае у меня появляется индикатор, но выполнение уходит на сервер и после выполнения индикатор перескакивает с 0% сразу на 100%.
15. TreeDogNight 15 08.07.16 06:33 Сейчас в теме
(14) doom2good, Меня тоже интересует этот вопрос.Ещё не нашли решение?
6. Yury1001 1430 03.05.12 12:24 Сейчас в теме
Отлично работает с выборкой результата запроса – ничего не сбивается.
Вызов сервера действительно затратный по времени, если делить это тысячи раз, будет ощутимо, и потому можно реализовать возврат по таймеру, ну там раз в 3 секунды, например.
7. Den_D 51 06.06.12 10:13 Сейчас в теме
Мне кажется к данной проблеме нет однозначного подхода и универсального решения.
Однако какие-то решения в определенных условиях являются лучшими.
8. juntatalor 61 08.07.13 02:16 Сейчас в теме
Раньше реализовывал индикацию данных также, как у вас.

Плюсы: точность отображения, легкий вывод сообщений на сервере, общее удобство

Минусы:
Первый и самый важный: Запрос.Выполнить.Выгрузить(). Для больших объемов данных это весьма затратно по временным ресурсам, по объему "отжираемой" памяти. Еще хуже, когда запрос содержит итоги, и нужно, например, выводить данные с группировками (т.е. для таблицы значений вы можете запомнить "текущую" строку, а для дерева - нет, и его все равно приходится переводить в таблицу значений). Это сильно усложняет код, делает его менее понятным и читаемым. Также достаточно велик трафик обмена клиент-сервер.

Сейчас перевел на работу в фоновых заданиях. У них тоже есть свои минусы: запускаются дольше, сложнее получать из них информацию, сложнее отладка, степень индикации не очень точна. Однако, там можно использовать Запрос.Выполнить().Выбрать(), да и в целом чисто "серверный" код без "дерганий" клиент<->сервер работает быстрее.

И насчет Данные = ПолучитьИзВременногоХранилища(АдресДанных) - они скорее всего кешируются в памяти, поэтому и вызов быстрый.
12. E_x 25.03.14 10:49 Сейчас в теме
Благодарю пользователя, это то, что надо. Немного адаптировал под работу со стандартным методом Состояние() и вообще огонь. Еще раз спасибо!
13. Bor_ka 80 20.10.15 23:09 Сейчас в теме
Попробовал, отлично работает. Спасибо автору.
Оставьте свое сообщение