Имя: Пароль:
1C
1С v8
Прогресс бар при работе с запросом
0 Azgerd
 
31.07.13
13:11
Есть Процедура &НаСервере, в которой выполняется запрос и обход результата запроса. Как правильно прицепить прогресс бар на цикл обхода.
Есть метод Состояние(<ТекстСообщения>, <Прогресс>,<Пояснение>,Картинка>), но он выполняется только на &Клиенте, вызвать процедуру с сервера на клиенте нельзя, есть ли какой-либо общепринятый метод запуска прогресс бара при работе с результатами запроса?
1 Maxus43
 
31.07.13
13:14
есть обходные пути, не совсем красивые v8: 1С8.2 прогрессбар при выполнении на сервере
2 Maxus43
 
31.07.13
13:15
+ только при переборе конечно, во время выполнения запроса - никак
3 Капитан О
 
31.07.13
13:16
общепринято фоновое задание запускать и картинку на клиенте крутить, пока задание работает
4 Godofsin
 
31.07.13
13:21
(3) Порно показывать?
5 Maxus43
 
31.07.13
13:22
(4) бородатого админа, ковыряющегося в сервере. Чтоб юзер понимал что происходит в данный момент
6 Полотенчик
 
31.07.13
13:25
Эффективная индикация в 8.2
http://infostart.ru/public/71407/
7 Darklight
 
31.07.13
13:30
(3)100% поддерживаю данное решение!
8 Fragster
 
модератор
31.07.13
13:34
(3)(7) а как оно должно работать в файловых базах до 18 (или какого-там) релиза?
9 Fragster
 
модератор
31.07.13
13:42
(6) эх, если бы контекст не надо было бы передавать туда-сюда для сохранения прогресса (а хранить на сервере) - затраты на вызов контекста намного меньше.
10 Fragster
 
модератор
31.07.13
13:43
на вызов без контекста
11 Darklight
 
31.07.13
13:43
(6)Идея хорошая, насколько это вообще доступно в 1С, но в реальных задачах с состояниями сложная, может упереться в объёмы таскаемых туда-сюда данные и в некоторых случаях - вообще не решаемая. Например, выполнение запроса вообще никак нельзя проиндицировать, а пользователю всё равно нужно показывать, что мол процесс идёт - имей терпение ;)
Прогресс бар - это конечно хорошо, но я бы просто остановился на фоновых зданиях с цикличной непрогрессирующей индикацией. Конечно - всё зависит от задач - если в задача в своей массе по про времени выполнения состоит не более чем из двух циклов перебора, где на каждую итерацию цикла уходит не боле секунды - то можно им прогресс бар сделать. Но чаще - это всё же просто долго выполняющиеся запросы.
(8)эээ.... ну файловые базы - это вообще особый случай. Он вообще очень плохо распараллеливается. Тут конечно можно поизвращаться - но я не стал бы. Если в файловой базе часто используются процессы, выполняющеся минутами - то имеется все 100% смысла переходить на серверную базу. Хоть бы с на бесплатную SQL-ку.
И ещё, фоновые задания появились ещё на 8.1 (если говорить о серверном использовании).
И ещё, управляемые формы нужны для тонкого клиента - а им нужен сервер 1С.
И ещё - управляемые формы можно и на толстом клиенте юзать - тогда должны работать алгоритмы обновления толстого клиента.
12 Azgerd
 
31.07.13
13:51
Как не вспомнить с настольгией Fox...
sele z_itog
Pb= CreateObject('ProgressBar')
_str=0
SCAN
    _str=_str+1
    =PB.ShowBar(100*_str/Recc('z_itog'),'идет расчёт')
   ВыполняетсяКакоетоДействие
ENDSCAN

и все дела!!!
13 Полотенчик
 
31.07.13
13:54
//ДанныеЗапроса - структура с запросом
//ЗаголовокФормы - Заголовок формы индикатора
//Результат     - возвращает только результат запроса.выполнить();
Функция ВыполнитьЗапросСИндикатором(ДанныеЗапроса,ЗаголовокФормы = Неопределено,КомментарийДействия = Неопределено) Экспорт
    
    Перем Результат;
    
    Запрос = ДанныеЗапроса.Запрос;    
    Попытка
        //так как это выполняется только для пакетных запросов то подключим МВ
        Если Запрос.МенеджерВременныхТаблиц = Неопределено Тогда
            Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
        КонецЕсли;
        ИсходныйТекст = Запрос.Текст;
        ТекстДляОбработки = ИсходныйТекст;
        ПакетЗапросов = Новый Массив;
        
        RegExp = Новый COMОбъект("VBScript.RegExp");
        RegExp.IgnoreCase = Истина;
        RegExp.Global = Истина;
        RegExp.MultiLine = Истина;
        
        RegExp.Pattern = "[^""]//.*$";
        ТекстДляОбработки = RegExp.Replace(ТекстДляОбработки, "");
        
        RegExp.MultiLine = False;
        RegExp.Pattern = "((ВЫБРАТЬ)[^;]*|(УНИЧТОЖИТЬ)[^;]*)";
        MC = RegExp.Execute(ТекстДляОбработки);
        Для Каждого M Из MC Цикл
            ПакетЗапросов.Добавить(M.Value);
        КонецЦикла;
        
        RegExp.Pattern = "((ПОМЕСТИТЬ)\s+[^;\s]*)";
        
        НомерЗапроса = 1;
        ФормаИндикации = ПолучитьОбщуюФорму("ХодВыполненияОбработкиДанных");
        ФормаИндикации.НаименованиеОбработкиДанных = ?(ЗаголовокФормы = Неопределено,"Обработка данных",ЗаголовокФормы);
        ФормаИндикации.КомментарийОбработкиДанных  = ?(КомментарийДействия = Неопределено,"Выполняется заполнение...",КомментарийДействия);
        ФормаИндикации.Открыть();
        СчетчикЦикла = 0;
        Для Каждого ТекЗапрос Из ПакетЗапросов Цикл
            СчетчикЦикла = СчетчикЦикла + 1;
            #Если ТолстыйКлиентОбычноеПриложение  Тогда
                ОбработкаПрерыванияПользователя();
            #КонецЕсли            
            НомерЗапроса = НомерЗапроса + 1;
            Запрос.Текст = ТекЗапрос;        
            Результат = Запрос.Выполнить();
            ФормаИндикации.Значение = СчетчикЦикла / ПакетЗапросов.Количество() * 100;
        КонецЦикла;
        
        ФормаИндикации.Закрыть();
    Исключение
        Результат = Запрос.Выполнить();
    КонецПопытки;
    Возврат Результат;    
    
КонецФункции
14 Darklight
 
31.07.13
13:56
(9)Кстати, ограничено, не очень эффективно, но контекст можно хранить на сервере:
1. В параметрах сеанса
2. Через сохранение значения на сервере во временном хранилище
ПоместитьВоВременноеХранилище(<Данные>, <Адрес>)
3. Через кеш возвращаемых значений процедур и функций общих модулей (с постоянном обновляемым входным параметром в виде, скажем UUID'а для хранения получения меняющихся данных) с минимальным (или требуемым) сроком хранения кешированного результата (задаётся в настрйоках кеширования модуля)
Последний самый извращённый вариант - но, на мой взгляд, наиболее эффективный. Мы так планируем хранить настройки работы учетной системы, сконфигурированные для конкретного пользователя, чтобы каждый раз не читать их из БД и по не  необходимости обновлять (по команде извне). В первую очередь это различные расширенные права и условия проверок, священные с объектами данных и движениями по регистрам.
15 Azgerd
 
31.07.13
14:05
(3)общепринято фоновое задание запускать и картинку на клиенте крутить, пока задание работает
Гы ! А картинка и так крутится - песочные часы :) чем не картинка.
16 Darklight
 
31.07.13
14:08
(13)Полезно, но не то :( или предлагаете весь запрос мельчить на кучу мелких частей пакета. А как же оптимизация производительности выполнения. Я, конечно, понимаю, что если рч5еь идёт в индикации, то это скорее всего не связано с массовой параллельный запускаемой обработкой данных типа "проведение документов". И чаще - указанный в данном примере подход нужен как раз только для построения отчетов в режиме "только чтение" и если он и так медленно выполняется, то можно  пренебречь замедлением, процентов на 10-20, из-за снижения эффективности построения общих планов выполнения SQL запросов (когда его начнут терроризировать мелкими последовательными запросиками).
17 Полотенчик
 
31.07.13
14:12
(16) Зачем специально мельчить? Когда строишь сложный запрос логично разбивать его на временные таблицы. Откройте ЗУП - там бешеные запросы с десятком таблиц...
ps сам я не сталкивался с такими уж долгими запросами, что приходится показывать какую-то индикацию. обычно у меня долгие запросы - rовнокод без учета как работает СУБД.
18 Полотенчик
 
31.07.13
14:14
+ (17) не в смысле что мои запросы - шлак тормозной, а по работе приходится сталкиваться с разными "художествами"
19 Darklight
 
31.07.13
14:14
(15)Надо что-то по больше покрасивее и повнушительнее для душевного спокойствия пользователей. Можно, например,запустить мини прогресс на три деления, циклически повторяемый, а через каждые три повторения (увеличвая каждлйы раз их на три для следующего вывода) ещё и выдавать сообщение пользовтаелю из списка (последовательно):
Ещё выполняется
Пока ещё выполняется
Нужно подождать - ещё выполоняется
Процесс оказалася долгим - ждите
Имейте терпение
Нужно подождать
Ещё немного
Ещё чуть чуть
Да... процесс затянлся
Очень долго, я знаю
Ждите-Ждите - процесс идёт

ну а далее можно подгрузить свежие анекдоты из
anekdot.ru/last/j.html
http://www.anekdot.ru/scripts/rand_anekdot.php?t=j
и потихоньку начать выводить (построчно)
Иногда выводя фразы из списка выше - для разнообразия и напоминания, что это проецесс ещё выполняется, а не просмотр анекдотов.
20 Darklight
 
31.07.13
14:16
(16)Просто если не мельчит, то эти составные части либо сами в целом будут долго выполняться, либо будет дисбаланс - одни частями будут очень быстрые - а другие медленные - и прогресс бар будет двигаться уж очень урывками - что очень сильно бесит!
21 Darklight
 
31.07.13
14:17
(16)(17)Я согласен - в ЗУП просто y.e.бные запросы!
22 dmpl
 
31.07.13
14:18
(11) Если у тебя запрос исполняется дольше 5-10 секунд - ты что-то делаешь не так. Прогресс-бар же реально нужен на задачи, выполняемые минутами и часами...
23 Darklight
 
31.07.13
14:27
(22)Конечно - не так наши пользователи слишком много вводят данных, и  слишком много их выводят, да ещё и за большие сроки. А я пишу запросы, которые выполняются за раз ;)
Но в любом случае - конечно всё зависит от задачи.
24 Darklight
 
31.07.13
14:30
А выполняющиеся часами вещи - вообще нужно распараллеливать (в инете есть ис таьи на эту тему и готовые решения). И строится это как раз на запуске множества фоновых заданий, с ожиданием их выполнения на клиенте. А раз они так долго выполняются, то их текущие состояния можно периодически и через БД (вспомогательный регистр) передавать на клиент (скажем, раз в минуту - это не будет накладно).
25 Azgerd
 
31.07.13
14:38
(11) дык речь идет не о том, за сколько времени выполняется запрос, а о том, сколько может длиться обход результата запроса и действия
в каждом шаге обхода, в запросе может быть всего 100 записей и он выполнится мгновенно, а во время обхода этих записей можно столько наваять, что этот обход будет длиться к примеру минут 10 (что во многих случаях вполне нормально). А за десять минут если на экране нифига не происходит у пользователя может лопнуть терпение...
26 dmpl
 
31.07.13
14:41
(23) На достаточно большой базе не видел ни одного запроса, который бы обоснованно выполнялся дольше указанного времени. Во всех случаях 5-10-60-минутного выполнения запроса путем приведения запроса к нормальному виду удавалось привести время его исполнения в приемлемые рамки 5-10 с.
27 Darklight
 
31.07.13
14:46
(26)Оптимизация - это не тот метод, который пропагандирует наша организация! Да и все предыдущие, где я работал, тоже :(
И куда ты денешься, если нужные данные можно будет достатать лишь... скажем из регистраторов, делая выборку по необходимости "с начала всех времён". Одной перестройкой запроса тут не обойтись. И а изменение сложившейся архитектуры, да ещё если она типовая, да ещё если пользователи за годы набили туда кучу данных и по закрывали периоды.... упаси боже - наши руководители никогда не дадут на это санкции и не выделать на это время!
28 Darklight
 
31.07.13
14:59
(25)ясно ясно... тут просто тематики смешались - нужно вернуться в русло исходной задачи. Смотри (6), (14), (19).
(6) конечно имеет смысл дорабатывать (см 14), а так же, может применятьт более сложные методики дробления кода, выполняемого на каждой итерации, цикла, с сохранением промежуточных результатов что-то типа такого

исходный цикл

Функция ОбработкаВсехДанных(Параметры)
     Состояние = ПолучитьСостояние(Параметры); //Какой-то код получения данных для обработки в цикле

Пока Состояние.Данные.Следующий() Цикл
   //Здесь часть кода 1
   //Здесь часть кода 2
   //Здесь часть кода 3
КонецЦикла;
//Здесь часть завершения всей обработки
возврат Результат;
КонецФункции


функция ОднаИтерация(Параметры)

Состояние = ПолучитьСостояние(Параметры); //см (14) - это задача в задаче

Если состояние.Часть=1 Тогда
    Если не Состояние.Данные.Следующий() Тогда
        //Здесь часть завершения всей обработки
        возврат Результат;
    КонецЕсли;
   //Здесь часть кода 1
   состояние.Часть=2
ИначеЕсли состояние.Часть=2 Тогда
   //Здесь часть кода 2
   состояние.Часть=3
ИначеЕсли состояние.Часть=3 Тогда
   //Здесь часть кода 3
   состояние.Часть=1
КонецЕсли;

//Код подготовки следующей итерации
возврат Параметры.ТекущийСчетчик+1;
конецфункции
29 Darklight
 
31.07.13
15:06
(28)Забыл вставить в конце где "Код подготовки следующей итерации" код сохранения обновлённого состояния (хранящегося на серверном контексте):
СохранитьСостояние(Состояние);

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

Да и ещё, конечно код можно усложнить - добавив как в (6) проверку времени и цикл на проведение нескольких итераций, если их обработка окажется короткой, чтобы не выполнение внутри функции ОднаИтерация(Параметры) шло порядка 1-4 секунд, и она сама бы контроллировала объём порции данных, которые готова уложить в расчетные 1-2 секунды своей работы. Универсальный код тут н напишешь - разбиение на части с контролем времени и его оценка - это индивидуальная задача уже из области искусства и конкретного приложения.
30 Darklight
 
31.07.13
15:37
(12)Кстати, это явно был не тонкий клиент ;) а на толстом вы такое и сейчас сделаете в 1С
31 Лефмихалыч
 
модератор
31.07.13
16:16
(0) исходя из того, что с сервера вызвать клиента не возможно, единственное средство - на сервере что-то складывать туда, откуда клиент с некоторой периодичностью может получать инфу о прогрессе. Временное хранилище подойдет.

Только это при любом раскладе - гонять инфу между клиентом и сервером, что не есть гуд
32 Darklight
 
31.07.13
16:22
(31)А что Вы там такое большое гонять собрались? Число состояния прогресса?.. раз в минуту?
33 Лефмихалыч
 
модератор
31.07.13
16:26
(32) я ни чего не собирался, автора спрашивай
34 Darklight
 
31.07.13
16:29
(33)Но Вы же написали "Только это при любом раскладе - гонять инфу между клиентом и сервером, что не есть гуд", тем самым высказали своё мнение. Я пытаюсь оценить это мнение.
35 Azgerd
 
31.07.13
16:52
(33) В форме есть кнопка, по этой кнопке запускается серверной процедура, где происходит выборка из запроса по определённым условиям документов СчетНаОплатуПокупателям, далее делаем обход этой выборки:
Пока Выборка.Следующий() Цикл
     Док = Выборка.ССылка.ПолучитьОбъект();
     НовыйДок = Док.Скопировать();
     НовыйДок.Дата = ЭтаФорма.Дата;
    ТЧ = НовыйДок.Услуги;
     Для Каждого Строка Из ТЧ Цикл
    Строка.Содержание = СокрЛП(Строка.Номенклатура)+"  "+СокрЛП(ЭтаФорма.Комент);    
    КонецЦикла;
    НовыйДок.Записать();
КонецЦикла;
Вроде и записей немного (порядка 100) а при выполнении процедуры задумываемся минуты на 2... Вот думал прогресс бар повесить, теперь возникают смутные сомнения...
36 Darklight
 
31.07.13
16:55
(35)Две минуты - это не срок
Да - а тут такие разговоры со сложными методами решений развели ;)
37 Azgerd
 
31.07.13
17:04
Хотелось бы иметь какие-то стандартные механизмы для обмена сервера и клиента. Такая же фигня возникает с методом Вопрос() - ну нужно иногда при работе с таблицой спросить у юзера о дальнейших действиях! Ан нет!!! Метод Вопрос() работает только на клиенте и казалось бы простейшее действие заставляет неимоверно изгаляться...
38 Конфигуратор1с
 
31.07.13
17:05
39 Darklight
 
31.07.13
17:05
Кстати, ещё одна прикольная мысль в голову пришла, но она специфическая:
СДЕЛАТЬ ВНЕШНЮЮ КОМПОНЕНТУ, которая могла бы соединяться сама с собой по TCP/IP и посылать сигнал через сеть. А в сигнале размещать сообщение с числом прогресса.
Тогда обработку стартовать в фоновом задании (от запроса до конца цикла), там же создавать внешнюю компоненту (на сервере) и к ней обращаться, для отправки сигнала. Естественно при вызове нужно будет ещё передать свои идентификационные данные (от компоненты, запущенной на клиенте, чтобы серверная нашла клиентскую). А на клиенте в обработчике получения внешнего сообщения (от клиентской компоненты) или в обработчике ожидания получать из компоненты текущее сообщение о прогрессе и обновлять прогресбар.
Заморочено: Да
Требует особых навыков программирования: Да
Возможны проблемы в настройке сетевого канала: Да
Возможны проблемы при VPN/WEB доступе: Да
Возмождны проблем в работке компоненты, написанной не на 1С: Да
Прогрессивно: Да
Технологично: Да
Круто: Да
Универсально: Да
Будете ли вы это делать: Нет
А я бы может и заморочился ;)
40 Darklight
 
31.07.13
17:07
(38)Ну там о секунда речь и о другом - о секундах порой надо думать. О часах надо думать. о минутах - неее
41 Лефмихалыч
 
модератор
31.07.13
17:09
(34) отлезь пожалуйста
42 Darklight
 
31.07.13
17:10
А кстати говоря ;) я в (14) упоминал в п.2
Читаем из синтаксис помощника ПОСЛЕДНИЙ АБЗАЦ "Примечание"

ПоместитьВоВременноеХранилище (PutToTempStorage)
Синтаксис:

ПоместитьВоВременноеХранилище(<Данные>, <Адрес>)
Параметры:

<Данные> (обязательный)

Тип: Произвольный.
Данные, которые необходимо поместить во временное хранилище.
<Адрес> (необязательный)

Тип: УникальныйИдентификатор; Строка.
Адрес во временном хранилище, по которому надо поместить данные. Или уникальный идентификатор формы, во временное хранилище которой, надо поместить данные и вернуть новый адрес.
В случае, если передается УникальныйИдентификатор формы, то значение будет автоматически удалено после закрытия этой формы.
Если параметр не указан, помещенное значение будет удалено после очередного запроса сервера из общего модуля, при контекстном и неконтекстном серверном вызове из формы, при серверном вызове из модуля команды или при получении формы.
Возвращаемое значение:

Тип: Строка.
Если в параметре <Адрес> указан уникальный идентификатор формы, то после помещения значения во временное хранилище формы, возвращает адрес.
Данные возвращаются только после того, как фоновое задание будет завершено.
Описание:

Сохраняет сериализуемое значение во временное хранилище.

Доступность:

Тонкий клиент, веб-клиент, сервер, толстый клиент, внешнее соединение.
Примечание:

Также позволяет поместить данные из фонового задания в родительский сеанс. Для этого следует в родительском сеансе поместить во временное хранилище пустое значение, передав идентификатор формы. Затем полученный адрес передать в фоновое задание через параметры фонового задания. Далее, если этот адрес использовать в параметре <Адрес>, то результат будет скопирован в сеанс, из которого было запущено фоновое задание.
43 Лефмихалыч
 
модератор
31.07.13
17:11
(37) отличный план спрашивать что-то с сервера у клиента. А если код регламентным заданием вызван, кто ответит? Александр Друзь?..
44 Darklight
 
31.07.13
17:11
(41)Ну, вот пошли наезды. Хотя я Вам ничего плохого не говорил. И вы сами "влезли"
45 Лефмихалыч
 
модератор
31.07.13
17:12
(44) так это ты ко мне с вопросами приклеился, а не я к тебе
46 Darklight
 
31.07.13
17:23
(43)Поддерживаю - это просто не гуд дизайн.
Вот они особенности настоящей клиент-серверной модели. К этому нужно привыкать. И стараться правильно создавать архитектуру решения, учитывающую такие, в общем-то, ключевые особенности данной модели. Нужно разделять алгоритм на части, чередующие между собой интерактивную и обрабатывающую часть. При этом, интерактивную, настоятельно рекомендуется иметь одну-две, ближе к началу (чередуя с обрабатывающей). Так же желательно сразу закладывать "интерактивные ответы по умолчанию", когда код не может быть возвращён пользователю, чтобы использовать их как настройки по умолчанию.
Примерно по такому приницыпу я не давно строил систему удалённого файлового хранилища. Нужно было работать с файлами через доступ с Сервера 1С, получая команды как интерактивно от клиента, так и от серверных процессов (например от обмена или подписки на события). Пришлось и интерактивную часть всю отдельно выносить (до начала основного процесса обработки файлов) и реализовывать управляющие алгоритмы, работающие вне интерактивного контура, по заложенным в настройках параметрам по умолчанию. В конце ещё можно было бы сделать финальную интерактивную часть, отложенного действия - когда клиент войдёт в данный контекст - сообщить ему о прошедших операциях и даже спросить подтверждение или изменение в их работе т.е. уже постфактум, с соответствующей переделкой работы. Вот так вот сложновато немного выходит в клиент-серверной архитектуре, но тут другого пути не было. Особенности разграничения доступности файловых ресурсов - доступ к хранилищу только у сервера.
И я как раз там использовал функцию ПоместитьВоВременноеХранилище()
(45)Мне было интересно, ладно, забудем!