gifts2017

Эффективная индикация в 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
290
.epf 6,22Kb 290 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. dushelov (Душелов) 06.06.10 15:58
Тема хорошая, вот только у меня все никак руки не дойдут до оптимизации того же моего шаблона.
2. Аркадий Кучер (Abadonna) 06.06.10 17:10
(1) А надо, что б дошли! А то мне самому придется думать ;)
3. Михаил Кос (mishakos) 09.06.10 08:26
Все хорошо, но на вывод индекса тратитьсяс 45% всего времени
4. Евгений Люлюк (Evg-Lylyk) 09.06.10 09:21
(3) Что есть индекс? на какой индекс???
5. Михаил Кос (mishakos) 09.06.10 11:12
я имел ввиду прогрессбар
6. Евгений Люлюк (Evg-Lylyk) 10.06.10 08:38
(5) Сейчас проверить не могу. Не пойму как он съедает 45% времени если вызывается Состояние 1-2 раза.
7. Николай Клементьев (Rusmus) 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) 23.09.10 00:19
Я думаю, что каждый раз время проверять тоже не стоит, а то на проверку времени может уходить все время :) :D
11. Евгений Люлюк (Evg-Lylyk) 23.09.10 10:44
(10) а куда денешся? Проверка врятли станет горячей точкой т.к. другие команды могут быть гораздо более долгими, а тут одна проверка.
12. Анатолий Ситников (acsent) 01.10.10 17:29
Откуда такой трафик в варианте без индикации?
13. Анатолий Ситников (acsent) 01.10.10 17:30
И на файловой базе бессмысленно проверять вызовы сервера
14. Евгений Люлюк (Evg-Lylyk) 01.10.10 17:53
(12) Добавляются строки в ТЗ (изменение формы вызов сервера)
(13) Кол. вызовов сервера сильно влияет на производительность 8.2 независимо от режима работы базы
15. Анатолий Ситников (acsent) 01.10.10 21:31
(14) в файловой версии вызов сервера значительно дороже. Примерно раза в 2
16. Евгений Люлюк (Evg-Lylyk) 02.10.10 00:42
(15) откуда данные? При каких условиях?
17. Анатолий Ситников (acsent) 03.10.10 01:01
Проводил мини тестирование
18. Александр Лукин (i_lo) 07.12.10 01:21
А как вывести индикатор для процесса, который идет на сервере и "каждую секунду" показывает на экране состояние, не возвращаясь в вызвавшую процедуру? Или это тоже, как фоновое задание?
19. Валерий Волошин (VVi3ard) 14.11.11 18:22
Мне кажется что правильнее было бы выводить индикатор не каждую секунду а каждый процент, на 8.1 я всегда сначала высчитывал шаг индикатора (сколько записей составляет 1%) и потом через каждое количество записей вызывал индикатор.

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

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

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

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

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

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

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