Эффективная индикация в 8.2

Опубликовал Евгений Люлюк (Evg-Lylyk) в раздел Программирование - Практика программирования

Выполнение кода (цикла) на сервере
Реализация индикации в 8.2 с минимальным числом серверных вызовов
Если кратко, решал задачу "как сделать эффективную индикацию 8.2"

Об общих особенностях реализации индикации описано в публикации Правильная индикация прогресса цикла (tormozit)

В данной публикации хочу рассмотреть особенность реализации эффективной индикации для платформы 8.2. Новая платформа имеет ряд неприятных особенностей (неудобств) в реализации индикации. Индикация процесса может быть произведена только на стороне клиента (&НаКлиенте) равно как и прерывание процесса пользователем, а большая часть наиболее длительных операций выполняется на сервере (в большинстве случаев без возможности сделать аналогичное на клиенте)

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

Требования эффективной индикации 8.2:

  • Минимальное число серверных вызовов (1 вызов в секунду)
  • Минимизировать объем передаваемого трафика (обрабатываемые данные должны быть на стороне сервера или передаваться в минимальном объеме)

Чтобы удовлетворить поставленным требованиям необходимо осуществлять обработку данных порциями т.е. процедура на сервере выполняет процесс (цикл) и следит за временем, и возвращается на клиент для индикации далее снова вызов сервера и так до окончания работы. Данная схема позволит гибко управлять индикацией.

Для примера делаю обработку, которая при нажатии «Начать» добавляет 10000 строк в таблицу.

Код примерно следующий:

&НаКлиенте
Процедура Начать(Команда)

   
Таблица.Очистить();

   
НачалоЗамера = СчетчикВремениВМс();

   
СделаноСч = Сделать(1);
    Пока
СделаноСч <> Неопределено Цикл
       
Состояние("Процесс", СделаноСч/100);
       
СделаноСч = Сделать(СделаноСч);
    КонецЦикла;

   
Сообщить(СчетчикВремениВМс() - НачалоЗамера);

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

&НаСервере
Функция Сделать(НачатьС)

   
ВремяНачала = ТекущаяДата();
    Для
Сч = НачатьС По 10000 Цикл
       
НоваяСтрока = Таблица.Добавить();
       
НоваяСтрока.Колонка = "Тестовая строка " + Сч;
        Если
ТекущаяДата() <> ВремяНачала Тогда
            Возврат
Сч+1;
        КонецЕсли;
       
//Если Сч%100 = 0 Тогда
        //  Возврат Сч+1;
        //КонецЕсли;
        //Если Сч%1000 = 0 Тогда
        //  Возврат Сч+1;
        //КонецЕсли;
   
КонецЦикла;

    Возврат Неопределено;

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

Характеристики различных вариантов реализации индикации в таблице:

Вариант

Время, с

Кол-во вызовов сервера

 

Трафик входящий, Кбайт

Трафик исходящий, Кбайт

 

Обработка порциями с индикацией раз в секунду

1,5

2

1196

2,7

Индикация каждые 100 строк

17,9

101

1300

136,6

… каждые 1000

3,2

11

1206

14,9

Без индикации

1,3

1

1195,7

1,4

Примечание: Платформа 8.2.11.229, конфигурации Athlon X2-2.2GHz, 4Gb, Windows 7 x64, файловая база

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

Обработка порциями (приведенный пример):

Достоинства: код выполняется на сервере; можно управлять частотой вызовов сервера (раз в секунду, раз на 100 записей или произвольный)

Недостатки: не всегда код можно адаптировать к подобной схеме; более сложная реализация

p.s.

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

Материалы на тему индикации:

Правильная индикация прогресса цикла (tormozit)

[8.2] Шаблон обработки с индикацией прогресса выполнения (управляемые формы) (dushelov)

 

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

Наименование Файл Версия Размер
Индикация82.epf
.epf 6,22Kb
06.06.10
291
.epf 6,22Kb 291 Скачать

См. также

Комментарии
1. dushelov (Душелов) 06.06.10 15:58 Сейчас в теме
Тема хорошая, вот только у меня все никак руки не дойдут до оптимизации того же моего шаблона.
2. Аркадий Кучер (Abadonna) 3667 06.06.10 17:10 Сейчас в теме
(1) А надо, что б дошли! А то мне самому придется думать ;)
3. Михаил Кос (mishakos) 09.06.10 08:26 Сейчас в теме
Все хорошо, но на вывод индекса тратитьсяс 45% всего времени
4. Евгений Люлюк (Evg-Lylyk) 2004 09.06.10 09:21 Сейчас в теме
(3) Что есть индекс? на какой индекс???
5. Михаил Кос (mishakos) 09.06.10 11:12 Сейчас в теме
я имел ввиду прогрессбар
6. Евгений Люлюк (Evg-Lylyk) 2004 10.06.10 08:38 Сейчас в теме
(5) Сейчас проверить не могу. Не пойму как он съедает 45% времени если вызывается Состояние 1-2 раза.
7. Николай Клементьев (Rusmus) 37 10.06.10 13:04 Сейчас в теме
На мой взгляд, стоит выделить основные действия в процедуры, чтобы сделать пример понятным и похожим на шаблон. Например, так:

&НаКлиенте
Процедура Операция()

Состояние = ПолучитьСостояние();
НачальнаяИнициализация(Состояние);

ПоследнееОбновлениеИндикатора = ТекущаяДата();
Пока Продолжать(Состояние) Цикл

ОбработкаПрерыванияПользователя();
ПоследнееОбновлениеИндикатора = СовершитьВитокИтерации(Состояние, ПоследнееОбновлениеИндикатора);
ОбновитьИндикатор(Состояние);

КонецЦикла;

ЗавершающаяИнициализация(Состояние);

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

&НаСервере
Процедура СовершитьВитокИтерации(Состояние, ПоследнееОбновлениеИндикатора)

Пока Продолжать(Состояние) Цикл

ТекущееПоложениеИндикатора = ТекущаяДата();
Если НеобходимоОбновлениеИндикатора(ПоследнееОбновлениеИндикатора, ТекущееПоложениеИндикатора) Тогда
Возврат ТекущееПоложениеИндикатора;
КонецЕсли;

Состояние = ОбработатьСостояние(Состояние);

КонецЦикла;

Возврат ТекущаяДата();

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

функции ПолучитьСостояние, НачальнаяИнициализация, Продолжать, ОбработатьСостояние, ЗавершающаяИнициализация оставить на разработку пользователю шаблона.
vkr; Evg-Lylyk; +2 Ответить
8. tuxik07 (tuxik07) 16.06.10 19:47 Сейчас в теме
а как сделать индикацию процесса выполняемого в фоновом задании?
9. dushelov (Душелов) 16.06.10 20:27 Сейчас в теме
10. Vladimir Glumov (Vovan58) 5 23.09.10 00:19 Сейчас в теме
Я думаю, что каждый раз время проверять тоже не стоит, а то на проверку времени может уходить все время :) :D
11. Евгений Люлюк (Evg-Lylyk) 2004 23.09.10 10:44 Сейчас в теме
(10) а куда денешся? Проверка врятли станет горячей точкой т.к. другие команды могут быть гораздо более долгими, а тут одна проверка.
12. Анатолий Ситников (acsent) 1010 01.10.10 17:29 Сейчас в теме
Откуда такой трафик в варианте без индикации?
13. Анатолий Ситников (acsent) 1010 01.10.10 17:30 Сейчас в теме
И на файловой базе бессмысленно проверять вызовы сервера
14. Евгений Люлюк (Evg-Lylyk) 2004 01.10.10 17:53 Сейчас в теме
(12) Добавляются строки в ТЗ (изменение формы вызов сервера)
(13) Кол. вызовов сервера сильно влияет на производительность 8.2 независимо от режима работы базы
15. Анатолий Ситников (acsent) 1010 01.10.10 21:31 Сейчас в теме
(14) в файловой версии вызов сервера значительно дороже. Примерно раза в 2
16. Евгений Люлюк (Evg-Lylyk) 2004 02.10.10 00:42 Сейчас в теме
(15) откуда данные? При каких условиях?
17. Анатолий Ситников (acsent) 1010 03.10.10 01:01 Сейчас в теме
Проводил мини тестирование
18. Александр Лукин (i_lo) 170 07.12.10 01:21 Сейчас в теме
А как вывести индикатор для процесса, который идет на сервере и "каждую секунду" показывает на экране состояние, не возвращаясь в вызвавшую процедуру? Или это тоже, как фоновое задание?
19. Валерий Волошин (VVi3ard) 36 14.11.11 18:22 Сейчас в теме
Мне кажется что правильнее было бы выводить индикатор не каждую секунду а каждый процент, на 8.1 я всегда сначала высчитывал шаг индикатора (сколько записей составляет 1%) и потом через каждое количество записей вызывал индикатор.

Тогда при любом раскладе будет только 100 вызов
20. Евгений Люлюк (Evg-Lylyk) 2004 14.11.11 22:29 Сейчас в теме
(18) посмотрите пример...
(19) вы сталкивались с 8.2? 100 это очень медленно и много трафика, хотя процесс мог произойти за 1 вызов
21. Валерий Волошин (VVi3ard) 36 18.11.11 12:31 Сейчас в теме
Сталкивался конечно, вот сейчас на ней родимой и работаю, да если у вас менее чем 100 операций планируется то да использовать мой подход не выгодно, если же 200-и выше и обработка занимает хотя бы минуту то в случае с вызовом каждую секунду будет 60 вызовов, если на каждый объект будет 200 вызовов.

А если в обработке меньше 100 элементов и обработка занимает 5-6 секунд особого смысла в индикаторе нет.
Данная обработка хороша тем что позволяет выбрать как выводить индикатор, (раз в секунду, раз на 100 записей или произвольный) было бы неплохо если бы автор добавил один раз за процент, но это можно и самим сделать без проблем.

Итого если у вас обрабатывается более 100 записей и процесс занимает более 100 секунд выгодно использовать вывод по процентам.
22. Евгений Люлюк (Evg-Lylyk) 2004 18.11.11 13:15 Сейчас в теме
(21) Данный подход как бы универсален и эффективен при разных условиях
VVi3ard пишет:
А если в обработке меньше 100 элементов и обработка занимает 5-6 секунд особого смысла в индикаторе нет.

Ну разве узнаешь сколько займет пока не начнешь делать... обработка послдених 10 элементов из 100 может занимать 90% времени обработки и т.д.

я стремился к след. использовать минимум вызовов и удовлетворительную оперативность обновления... ИМХО раз в секунду то что надо
В примере чисто индикатор, но можно же выводить количество оставщегося времени осталось 1:03 или количество уже обработанных записей, сколько прошло и т.д.. Влияние вывода индикатора при вызове раз в секунду очень мало.

VVi3ard пишет:
Итого если у вас обрабатывается более 100 записей и процесс занимает более 100 секунд

Если обработка одного объекта будет больше секунды то обновление будет больше. Например проведение документов... проведение занимает 3 с. обновление будет 3с.

VVi3ard пишет:
Мне кажется что правильнее было бы выводить индикатор не каждую секунду а каждый процент, на 8.1 я всегда сначала высчитывал шаг индикатора (сколько записей составляет 1%) и потом через каждое количество записей вызывал индикатор.

Неизвестно сколько будет идти обработка по времени и насколько равномерно время распределится на обрабатываемые объекты, 1% может быть обработан как за 5с так и за 0.5
Вот смотрите... пользователю собственно пофиг на 1% на 5%, ИМХО главное чтобы он не думал что зависло и видел время которое осталось... чтобы знать идти курить или подождать (разве поймет он сколько осталось по процентовке это нужно посчитать сколько времени это заняло и т.д.)

Суть метода в том чтобы с сервера вернутся на клиент отобразить индикатор, а потом назад работать и тд.
возьмите реализацию протестируйте свои предложения
23. nitro (nitr02k) 06.12.11 15:17 Сейчас в теме
Я так думаю что эти цифры сравнения относительны может у меня сеть 1 гб ))
24. Юрий Зайцев (Yury1001) 1418 02.01.12 15:05 Сейчас в теме
Это всё конечно интересно
(19) (20) да и возврат для индикации можно сделать комбинированный: раз в 1% но не чаще секунды.
Вот только как быть, если я загружаю, например, данные из Excel, ну там 6-7 000 строк – не открывать же книгу на сервере каждые 1 секунду или 100 раз?
25. Юрий Зайцев (Yury1001) 1418 02.01.12 15:14 Сейчас в теме
(8) (9) а можно писать состояние в текстовый файл, а на какой нибудь форме его смотреть, эдакую консоль состояний сделать.
Есть же ПодключитьОбработчикОжидания() для формы? Только, честно, я не проверял.
26. Евгений Люлюк (Evg-Lylyk) 2004 02.01.12 16:52 Сейчас в теме
(24)
для индикации можно сделать комбинированный: раз в 1%, но не чаще секунды.

а если 1% делается 5 минут, пользователь будет думать что зависло

Вот только как быть, если я загружаю, например, данные из Excel, ну там 6-7 000 строк – не открывать же книгу на сервере каждые 1 секунду или 100 раз?

Файл передается на сервер и открывается один раз... далее обработка или еще что то там
27. Юрий Зайцев (Yury1001) 1418 02.01.12 17:23 Сейчас в теме
(26) ну я имел ввиду или или что раньше наступит.
А про «открывается один раз» позвольте: при возврате с сервера все переменные обнуляются, где ж мне объект оставить?
28. Евгений Люлюк (Evg-Lylyk) 2004 02.01.12 19:18 Сейчас в теме
(27)
А про «открывается один раз» позвольте: при возврате с сервера все переменные обнуляются, где ж мне объект оставить?

во временном хранилище ПолучитьИзВременногоХранилища/ПоместитьВоВременноеХранилище
ну я имел ввиду или или что раньше наступит.
особо смысла не вижу расчета 1% и так достаточно оперативное обновление пользователь видит что процесс жив и насколько он двигается.
Yury1001; +1 Ответить
29. Денис (Den_D) 47 06.06.12 10:12 Сейчас в теме
Эту эпопею можно назвать - Битва за индикатор)))
30. Алексей Попов (Aleskey_K) 10 10.06.13 15:28 Сейчас в теме
(8) tuxik07, в цикле писать СобщениеПользователю, а в обработчике ожидания считывать их методом ПолучитьСообщенияПользователю. Делалось для файлового и серверного вариантов.
Насколько я знаю, через временное хранилице удобнее, но медленнее и задействуется дисковая подсистема.
Оставьте свое сообщение