Отправляет email-рассылки с помощью сервиса Sendsay

Школа 1С

  Все выпуски  

1С:Школа : 'Быстрые' и 'медленные' переменные


Информационный Канал Subscribe.Ru

1С:Школа
Выпуск 52
«Быстрые» и «медленные» переменные

Здравствуйте, уважаемые Ученики, Коллеги и Читатели!

В этом выпуске речь пойдет об оптимизации. Обычно клиент-заказчик хочет, чтобы программы, работающие у него, стоили мало, делали все правильно и быстро, были красивыми и простыми в использовании. Для того чтобы программы работали быстро, программист применяет те или иные методы оптимизации. Сегодня мы обсудим, что можно сделать, чтобы программы, написанные на встроенном языке системы «1С:Предприятие», работали быстрее.

Вопрос этот не праздный. В качестве иллюстрации приведу историю, произошедшую в действительности. В одну из московских фирм 1С:Франчайзи обратился крупный региональный клиент с просьбой ускорить ведущийся в программе «1С:Зарплата и Кадры 7.7» расчет заработной платы более чем двух тысяч сотрудников. Конфигурация была основана на Типовой, некоторые изменения были внесены местными специалистами. Ежемесячно запускаемый расчет (иногда, если требовался пересчет, то расчет запускался несколько раз в месяц) занимал у Заказчика шесть часов. Формулируя задачу, Клиент обозначил дополнительные условия: ускорение расчета должно быть достигнуто только штатными средствами 1С:Предприятия (то есть без использования дополнительных программ вроде TurboBL, «Быстрых регистров» и др.) и без изменения состава аппаратного обеспечения и настроек других программ Заказчика. Клиент также оговорил, что ускорение менее чем в два раза его не интересует. Исполнитель и Заказчик договорились, что если в результате доработок будет достигнуто ускорение в два раза, сумма вознаграждения будет одной, если в три раза – вознаграждение будет больше, в четыре раза – еще больше, и т.д. Изучив конфигурацию Заказчика, специалисты Исполнителя смогли внести в нее такие изменения, которые привели к ускорению расчета заработной платы в три с половиной раза!

Думаю, эта история лишний раз наглядно показывает, что оптимизация и ускорение не только возможны, но и востребованы.

Считается, что оптимизация бывает нескольких видов. Это и оптимизация структур данных, и оптимизация алгоритмов работы, и оптимизация использования языковых средств. Приведу примеры. Программа будет работать медленно, если при реализации выбран неэффективный алгоритм (скажем, поиск полным перебором). Ни один быстрый алгоритм не будет работать быстро, если он работает с неудачно выбранными структурами данных. Но даже быстрый алгоритм с оптимальными структурами данных можно существенно замедлить, если неправильно использовать предоставленные системой языковые средства. В этом выпуске мы будем говорить именно о языковых средствах, которые нам доступны при использовании системы «1С:Предприятие 7.7», а точнее – о «быстрых» и «медленных» переменных.

При конфигурировании 1С:Предприятия 7.7 программист может использовать переменные нескольких видов. Скажем, в модуле формы внутри процедуры возможна работа с экспортируемыми переменными Глобального модуля, с переменными, объявленными в этом модуле, с переменными, объявленными в этой процедуре, с необъявленными переменными этой процедуры и с данными в реквизитах формы (доступ к ним осуществляется как к обычным переменным модуля). Однако, как оказалось, использование разных видов переменных приводит к разному времени исполнения программного модуля.

Небольшое исследование мы проведем, решая классическую задачу – обмен значениями двух переменных. Например, если в переменной ПервоеЧисло хранится число 154, а в переменной ВтороеЧисло – 602, то в результате выполнения операции обмена значениями мы должны получить в переменной ПервоеЧисло – 602, а в переменной ВтороеЧисло – 154. Метод решения этой задачи мы будем использовать тоже классический – обмен будем производить, используя третью переменную в качестве временного хранилища. Из-за разных способов записи в тексте программы его еще часто называют «метод паровозика»:
      Временное = ПервоеЧисло; ПервоеЧисло = ВтороеЧисло; ВтороеЧисло = Временное;
или «метод крест-накрест»:
      Временное   = ПервоеЧисло;  
      ПервоеЧисло = ВтороеЧисло
;  
      ВтороеЧисло = Временное;    

Разумеется, замер одиночной операции обмена значениями не даст нам достаточно точной и достаточно достоверной информации о времени ее выполнения. Поэтому для получения полной картины мы замерим время выполнения миллиона таких операций. Заставить систему выполнить такое количество операций нам поможет цикл со счетчиком. Общая конструкция будет выглядеть следующим образом:
      Для СчетчикЦикла=1 по 1000000 Цикл
            Временное   = ПервоеЧисло
;  
            ПервоеЧисло = ВтороеЧисло
;  
            ВтороеЧисло = Временное
;    
      КонецЦикла;                       

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

Оговорим сразу: мы будем измерять скорость обмена значениями, являющимися датами. Задача эта встречается довольно часто. Ввел, скажем, пользователь в поля, описывающие период отчета, даты в обратном порядке. То есть дата окончания периода раньше, чем дата его начала. Можно, конечно, пользователя отругать и заставить ввести их снова. А можно просто поменять даты местами и спокойно формировать отчет дальше.

Опишем конфигурацию, с которой будем производить эксперименты. Это – оригинальная конфигурация, созданная, что называется, «с чистого листа». В ней есть Глобальный модуль следующего содержания:
Перем глСчетчик Экспорт; //Счетчик цикла из Глобального модуля        
Перем
глДатаНач Экспорт; //Первая дата из Глобального модуля          
Перем глДатаКон Экспорт;
//Вторая дата из Глобального модуля          
Перем глВрмДата Экспорт;
//Временное хранилище из Глобального модуля  
Также создадим в конфигурации Обработку ОбменДат, на ее форме разместим:
 - реквизит диалога фрмСчетчик (тип: Число, 7), невидимый;
 - реквизит диалога фрмДатаНач (тип: Дата);
 - реквизит диалога фрмДатаКон (тип: Дата);
 - реквизит диалога фрмВрмДата (тип: Дата), невидимый;
 - кнопку Замер, которая при нажатии вызывает процедуру Замер().
Модуль этой Обработки будет выглядеть следующим образом:
Перем модСчетчик; //Счетчик цикла из модуля обработки                  
Перем модДатаНач;
//Первая дата из модуля обработки                   
Перем модДатаКон;
//Вторая дата из модуля обработки                   
Перем модВрмДата;
//Временное хранилище из модуля обработки           
                                                                      
Процедура
Замер
()                                                     
      Перем
прСчетчик;
//Счетчик цикла из этой процедуры              
      Перем прДатаНач;
//Первая дата из этой процедуры                
      Перем прДатаКон;
//Вторая дата из этой процедуры                
      Перем прВрмДата;
//Временное хранилище из этой процедуры        
                                                                      
     
// РЕКВИЗИТЫ ФОРМЫ                                              
      Состояние("Реквизиты формы"
);                                   
     
// Инициализация переменных                                     
     
//   не нужна,                                                  
     
//   Пользователь введет сам                                    
     
// Цикл обменов                                                 
      Для фрмСчетчик=1 по 1000000
Цикл                                
           
фрмВрмДата = фрмДатаНач
;                                  
           
фрмДатаНач = фрмДатаКон
;                                  
           
фрмДатаКон = фрмВрмДата
;                                  
      КонецЦикла;                                                     
                                                                      
     
// ПЕРЕМЕННЫЕ ИЗ ГЛОБАЛЬНОГО МОДУЛЯ                              
      Состояние("Переменные из Глобального модуля"
);                  
     
// Инициализация переменных                                     
      глДатаНач = фрмДатаНач
;                                         
     
глДатаКон = фрмДатаКон
;                                         
     
// Цикл обменов                                                 
      Для глСчетчик=1 по 1000000
Цикл                                 
           
глВрмДата = глДатаНач
;                                    
           
глДатаНач = глДатаКон
;                                    
           
глДатаКон = глВрмДата
;                                    
      КонецЦикла;                                                     
                                                                      
     
// ПЕРЕМЕННЫЕ МОДУЛЯ ОБРАБОТКИ                                  
      Состояние("Переменные модуля Обработки"
);                        
     
// Инициализация переменных                                     
      модДатаНач = фрмДатаНач
;                                        
     
модДатаКон = фрмДатаКон
;                                        
     
// Цикл обменов                                                 
      Для модСчетчик=1 по 1000000
Цикл                                
           
модВрмДата = модДатаНач
;                                  
           
модДатаНач = модДатаКон
;                                  
           
модДатаКон = модВрмДата
;                                  
      КонецЦикла;                                                     
                                                                      
     
// ПЕРЕМЕННЫЕ, ОБЪЯВЛЕННЫЕ В ЭТОЙ ПРОЦЕДУРЕ                     
      Состояние("Переменные, объявленные в этой процедуре"
);          
     
// Инициализация переменных                                     
      прДатаНач = фрмДатаНач
;                                         
     
прДатаКон = фрмДатаКон
;                                         
     
// Цикл обменов                                                 
      Для прСчетчик=1 по 1000000
Цикл                                 
           
прВрмДата = прДатаНач
;                                    
           
прДатаНач = прДатаКон
;                                    
           
прДатаКон = прВрмДата
;                                    
      КонецЦикла;                                                     
                                                                      
     
// НЕОБЪЯВЛЕННЫЕ ПЕРЕМЕННЫЕ                                     
      Состояние("Необъявленные переменные"
);                          
     
// Инициализация переменных                                     
      ноДатаНач = фрмДатаНач
;                                          
     
ноДатаКон = фрмДатаКон
;                                         
     
// Цикл обменов                                                 
      Для ноСчетчик=1 по 1000000
Цикл                                 
           
ноВрмДата = ноДатаНач
;                                    
           
ноДатаНач = ноДатаКон
;                                    
           
ноДатаКон = ноВрмДата
;                                    
      КонецЦикла;                                                     
                                                                      
      Предупреждение(
"Всё!"
);                                         
КонецПроцедуры                                                        

Таблицу этой Обработки можно удалить.

Измерение времени выполнения отдельных блоков будем выполнять, используя встроенную возможность Отладчика системы «1С:Предприятие 7.7», которая называется Замер производительности. Начать или закончить замер можно с помощью специальной кнопки на панели инструментов или выбрав в меню «Отладка» пункт «Замер производительности».

Приступаем к измерениям! Запускаем 1С:Предприятие с нашей конфигурацией. Вызываем созданную нами Обработку (самые предусмотрительные Читатели, я уверен, уже вынесли вызов Обработки в пользовательское меню, не сделавшие этого могут вызвать Обработку, используя меню «Операции», пункт «Обработки»). Вводим Дату начала и Дату окончания. Вызываем Отладчик, начинаем замер производительности. Возвращаемся в окно 1С:Предприятия, нажимаем кнопку Замер, ожидаем некоторое время до появления на экране окна с надписью «Всё!», нажимаем кнопку ОК, возвращаемся в окно Отладчика и завершаем замер производительности. В появившемся окне внимательно изучаем результаты.

Для того чтобы получить окончательные результаты, останется только просуммировать для разных блоков данные по времени выполнения входящих в блоки строк модуля. Пытливых и недоверчивых отсылаем выполнять эту работу самостоятельно. Остальным же сообщим полученные выводы, ведь «Школа 1С» уже провела все подсчеты, причем эксперименты проводились более обширные, на нескольких компьютерах и при разном количестве повторений операций.

Итак, рейтинг видов переменных выглядит следующим образом. Звание самых медленных переменных получают реквизиты формы. Переменные, экспортируемые из Глобального модуля, являются более быстрыми, операции с ними выполняются в 3-3.5 раза быстрее, чем с реквизитами формы. Переменные, объявленные в модуле, быстрее Глобальных примерно в 1.5 раза. Выигрыш во времени от их использования вместо реквизитов формы составляет 4.5-5 раз. Ну а звание самых быстрых переменных делят между собой переменные, объявленные в процедуре, и необъявленные переменные. В разных экспериментах то один вид, то другой слегка вырывался вперед, однако разница между ними не превышала полпроцента. Впрочем, эти переменные ненамного обогнали и объявленные в модуле – примерно на один процент.

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

В будущем, в выпусках нашей рассылки, мы еще будем возвращаться к теме оптимизации и ускорения работы программ системы «1С:Предприятие». А на сегодня на этом всё!

С уважением, директор Школы 1С Владислав Аврутин.


http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.school1c
Отписаться

В избранное