gifts2017

1С:Предприятие 7.7. Оптимизация.

Опубликовал Алексей Константинов (alexk-is) в раздел Программирование - Практика программирования

Разгоняем 1С:Предприятие 7.7. Выжимаем последние соки.

Хочу сразу оговориться (уточнить), что в статье описаны приемы, которые позволяют на моем домашнем компьютере рассчитывать 11000 абонентов и при этом формировать и рассчитывать 60000 записей в журнал расчетов за 26 секунд в монопольном режиме в DBF версии 1С:Предприятия 7.70.025 на компоненте 1С:Расчет (ОС Windows XP). Объем базы данных около 350 Mb.

Постараюсь наиболее полно отразить замечания из комментариев к статье...

Только качественный контент

Мысль написать статью у меня появилась после того, как был задан вопрос в процессе обсуждения конфигурации для Абонентского отдела водоканала. Вопрос был прост: «Какие проблемы встречались, и какие методы использовались для повышения производительности».

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

  1. Увеличить вычислительные мощности (железо)
  2. Сократить количество выполняемых действий (программа)

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

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

Начнем с простого и очевидного. Первый прием. Использование библиотек turbobl.dll, автор Александр Орефков или 1cpp.dll. Если рассматривать типовые конфигурации фирмы 1С для 1С:Предприятия 7.7, то наиболее заметный эффект использования данных библиотек проявляется в конфигурациях «1С:Зарплата и кадры 7.7» и «1С:Комплексная конфигурация 7.7». В данном случае для использования этих библиотек не требуется значительная модификация кода конфигурации. Эффект наступает сразу после загрузки библиотек даже в типовых конфигурациях, т.к. рост производительности происходит на уровне платформы 1С:Предприятия 7.7. В базовых версиях можно воспользоваться обработкой, которая загрузит одну из библиотек.

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

ИмяБиблиотеки = КаталогПрограммы() + "TurboBL.dll";
Если ФС.
СуществуетФайл(ИмяБиблиотеки) = 1 Тогда
    ЗагрузитьВнешнююКомпоненту(
ИмяБиблиотеки);
Иначе
   
ИмяБиблиотеки = КаталогИБ() + "TurboBL.dll";
    Если ФС.
СуществуетФайл(ИмяБиблиотеки) = 1 Тогда
        ЗагрузитьВнешнююКомпоненту(
ИмяБиблиотеки);
    КонецЕсли;
КонецЕсли;

Остальные приемы потребовали более значительной модификации программного кода конфигурации.

Второй прием связан с сокращением общего количества точек (разыменований) при выполнении кода. Этот прием является продолжением или частной модификацией первого приема. Т.е. рост производительности достигается за счет сокращения количества операций разыменования.

Например:

Форма.Закладки.Добавить("Общий,Кнопки", "Общий");
Форма.Закладки.Добавить("Льготы,Кнопки", "Льготы");
Форма.Закладки.Добавить("Объекты,Кнопки", "Объекты");

Заменяем на

СписокЗакладок = Форма.Закладки;
СписокЗакладок.Добавить("Общий,Кнопки", "Общий");
СписокЗакладок.Добавить("Льготы,Кнопки", "Льготы");
СписокЗакладок.Добавить("Объекты,Кнопки", "Объекты");

В данном случае удалось избавиться от двух точек и, несмотря на одну лишнюю команду, получить некоторый рост производительности. Этот пример демонстрирует лишь общий принцип, а не частный случай. Сравнить результат выполнения блоков команд можно, используя в отладчике замер производительности.

Результат применения второго приема можно посмотреть здесь: Дополнительные материалы к статье.

Третий прием связан с сокращением количества используемых в конфигурации команд СоздатьОбъект(). В конфигурации для Абонентского отдела водоканала команды СоздатьОбъект("СписокЗначений") и СоздатьОбъект("ТаблицаЗначений") встречаются 1 раз только в глобальном модуле конфигурации. Например:

Перем глПустаяТаблицаЗначений Экспорт;

//*******************************************************
//  глТипТаблицаЗначений()
//
//  Параметры:
//      нет
//
//  Возвращаемое значение:
//      Пустая таблица значений
//
//  Описание:
//      Возвращает объект типа "ТаблицаЗначений"
//      Работает в 5-6 раз быстрее чем использование
//      конструкции СоздатьОбъект("ТаблицаЗначений")
//
Функция глТипТаблицаЗначений() Экспорт
    Перем
ТаблицаЗначений;

   
глПустаяТаблицаЗначений.Выгрузить(ТаблицаЗначений);
    Возврат
ТаблицаЗначений;

КонецФункции
// глТипТаблицаЗначений

глПустаяТаблицаЗначений = СоздатьОбъект("ТаблицаЗначений");

Далее по тексту всех модулей использование вызовов может быть следующим:

Процедура ПроцедураСозданияТаблиц()
    Перем
Таблица1, Таблица2, Таблица3;

   
глПустаяТаблицаЗначений.Выгрузить(Таблица1);
   
Таблица1.НоваяКолонка("ТекущийЭлемент");
   
Таблица1.НоваяКолонка("ТЗ");

    Пока <
УсловиеЦикла> Цикл
       
// Запишем таблицу в таблицу таблиц
       
Таблица1.НоваяСтрока();
       
Таблица1.ТекущийЭлемент = ТекущийЭлемент;
       
Таблица1.ТЗ = глТипТаблицаЗначений();
    КонецЦикла;

КонецПроцедуры
//глИнициализацияВидовТарифов

Замеры производительности показали, что в случае использования библиотек turbobl.dll или 1cpp.dll наибольшее ускорение дают команды глПустаяТаблицаЗначений.Выгрузить() и глПустойСписокЗначений.Выгрузить(). При этом может быть ускорение в 50-55 раз. Если библиотеки не используются, то ускорение только в 5-6 раз - тоже неплохо. Но есть прием описанный в 7 посте этой статьи, который при работе со СпискомЗначений дает ускорение в 15 раз и это без использования библиотек: ЗначениеИзСтрокиВнутр("{""VL"",{}}").

Результат применения третьего приема можно посмотреть здесь: Дополнительные материалы к статье.

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

ЖУ = СоздатьОбъект("ЖурналРасчетов.Учет");
ЖР
= СоздатьОбъект("ЖурналРасчетов.Учет");

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

Результат применения четвертого приема можно посмотреть здесь: Дополнительные материалы к статье.

Пятый прием связан с использованием эффективных порций обрабатываемой информации. Эффективные порции могут измеряться в строках документов, количестве записей или количестве сотрудников. Эти порции чтения-записи обрабатываются в транзакции. Следует отметить, что размер эффективных порций зависит от режима работы 1С:Предприятия 7.7. В монопольном режиме работы размер эффективных порций может быть в 2-4 раза больше, чем в разделенном режиме. Это связано с обработкой блокировок, которые создают дополнительный трафик в разделенном режиме.

В этом приеме есть некоторое противоречие, потому что транзакции призваны обеспечить целостность выполняемых изменений в информационной базе. А при использовании данного приема документ проводится несколькими транзакциями. Сбой при проведении в одной из транзакций может привести к частичному проведению документа, что, конечно же, исказит картину целостности информации. К счастью таких проблем за 12 лет не возникало.

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

Рассмотрим возможную реализацию данного приема чуть подробнее.

  1. Отключается автоматическое удаление движений документа
  2. В форме документа создается процедура, которая запускает на проведение документ блоками
  3. В модуле документа процедура проведения изменяется на работу с блоками данных
  4. В модуле документа добавляется процедура отмены проведения
  5. В глобальном модуле добавляются процедуры на события пометки на удаление и отмены проведения документов с "особой" обработкой документов без автоматического удаления движений
  6. Изменяется групповая обработка документов, которая для документов без автоматического удаления движений открывает форму с передачей параметра запускающего документ на проведение

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

Примеры реализации можно посмотреть в типовых конфигурациях 1С или здесь http://www.infostart.ru/public/18657/

Пример обработки блоков с передачей указателя строки документа.
Текст в модуле формы документа

//*******************************************************
//  __Провести()
//
//    Параметры:
//      Нет
//
//  Описание:
//      Сохраняет и проводит документ. При этом делит процесс проведения на
//      несколько транзакций, что значительно сокращает общее время
//      проведения документа.
//

Процедура __Провести()
     
    ПриЗаписи
();
    Если СтатусВозврата() = 0 Тогда
        Возврат;
    ИначеЕсли
Модифицированность
() = 1 Тогда
        Записать();
    ИначеЕсли
Выбран
() = 0 Тогда
        Записать();
    КонецЕсли;
 
    Если
глУдалитьДвиженияДокумента(ТекущийДокумент
()) = 0 Тогда
        Возврат
    КонецЕсли;

 

    ФлагПроведения = 1;
   
Сч = 1; КоличествоСтрок = КоличествоСтрок
();
    Пока
Сч <= КоличествоСтрок
Цикл
        ФлагПроведения = Провести(,Сч
);
        Если ФлагПроведения = 0 Тогда
            Прервать
        КонецЕсли;
        Сч = Сч
+ 500;
    КонецЦикла;

    Если ФлагПроведения = 0 Тогда
       
глУдалитьДвиженияДокумента(ТекущийДокумент());
       
СделатьНеПроведенным();
    КонецЕсли;
 
КонецПроцедуры
//__Провести

Текст в модуле документа

//*******************************************************
Процедура ОбработкаПроведения(Режим = 0)
   
// Режим = 0 - провести документ без формирования движений по документу
    // Режим > 0 - допроведение документа

 
    Если ГрупповаяОбработка() = 1 Тогда
        глСообщениеГрупповойОбработки(ТекущийДокумент
);
        СтатусВозврата(0); Возврат;
    ИначеЕсли
Режим
= 0 Тогда
        Возврат;
    КонецЕсли;
 
    Для
Сч = Режим По Мин(Режим + 499, КоличествоСтрок()) Цикл
        ПолучитьСтрокуПоНомеру(Сч);
        // Текст обработки строк документа
    КонецЦикла;
 
КонецПроцедуры //ОбработкаПроведения

Шестой прием связан с заменой использования для объектов типа СписокЗначений метода Принадлежит() на метод НайтиЗначение(). Это связано с особенностями данных методов. Вот описание из метода Принадлежит():

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

Как показали замеры (в том числе и в отладчике) в большинстве случаев заявленная оптимизация не работает. Из около 100 проверенных строк кода оптимизация отработала только в 2-х. Во всех остальных случаях получалось ускорение в 2-3 раза на замененной команде. При сотнях тысяч повторений эффект получается довольно значительный. К сожалению мне не удалось определить точно по какому принципу определяется "массовое последовательное сравнение" и включается оптимизация, поэтому предлагаю протестировать конкретный кусок кода до и после применения данного приема.

Результат применения шестого приема можно посмотреть здесь: Дополнительные материалы к статье.

Седьмой прием касается передачи параметров между функциями в модуле. Довольно часто математика конфигурации развалена по функциям и процедурам. При этом одни и те же переменные передаются между функциями и процедурами по ссылкам. На передачу и прием параметров также тратится некоторое время. Эти переменные можно объявить глобальными, если обработка происходит в глобальном модуле или объявить переменными модуля, если обработка происходит в модуле формы или модуле объекта.

Результат применения седьмого приема можно посмотреть здесь: Дополнительные материалы к статье.

Восьмой прием связан с сокращением повторных обращений к базе данных в рамках, например, проведения документа. Т.к. операции чтения из базы данных являются более медленными, чем, например, из ТаблицыЗначений.

Пример использования данного приема применительно к конфигурациям «1С:Торговля и склад 7.7» и «1С:Комплексная 7.7» можно посмотреть здесь Распределение суммы по таблице значений

Разумеется, в конфигурации Абонентский отдел водоканала применяется еще множество других приемов. Но это касается в большей степени рефакторинга.

Да, еще про печать. Тема от ineoosaki. Вот несколько приемов. При выводе печатных форм оптимизировать можно код и таблицу.

Девятый прием. Выражения, выводимые при печати лучше рассчитывать в модуле, а не в таблице использующейся в качестве шаблона. Данная рекомендация есть на диске ИТС. А также при заполнении данных в областях использовать поименнованые секции.

Результат применения девятого приема можно посмотреть здесь: Печать этикеток. Быстрее, быстрее, быстрее.

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

Результат применения десятого приема можно посмотреть здесь: Печать этикеток. Быстрее, быстрее, быстрее.

Одиннадцатый прием. Для больших таблиц также применим метод определения эффективной порции. Т.е. большой отчет может быть разбит на несколько небольших отчетов. Это тоже позволит поднять производительность печати.

Результат применения одиннадцатого приема можно посмотреть здесь: Печать этикеток. Быстрее, быстрее, быстрее.

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


Это к 1С не имеет прямого отношения, но все-таки. Так как большинство принтеров имеют встроенные шрифты, то для повышения скорости печати можно уменьшить "качество" печати до 150 dpi. Буквы останутся в идеальном состоянии, а при печати таблиц для вертикальных и горизонтальных линий такой точности более чем достаточно. С учетом того, что MXL это таблица, то ускорение будет, даже если в печатной форме нет рамок.

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

Дополнительные материалы к статье.


Про экранные формы. Раньше, когда о Core 2 Quad никто даже не думал, быстрая прорисовка экранных форм была достаточно больной проблемой. Возникали промигивания при переключении по закладкам. Значительные торможения при изменении реквизитов в формах или при пролистывании списков. В каких местах кода происходят задержки можно посмотреть в отладчике с помощью замера производительности.

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

//*******************************************************
Процедура ПриОткрытии()

    СписокЗакладок = Форма.Закладки;
    СписокЗакладок.Добавить("Общий,Кнопки", "Общий");
    СписокЗакладок.Добавить("Льготы,Кнопки", "Льготы");
    СписокЗакладок.Добавить("Объекты,Кнопки", "Объекты");
 
КонецПроцедуры //ПриОткрытии

//*******************************************************
Процедура ПриОткрытиПриВыбореЗакладки(НомерЗакладки, ЗначениеЗакладки)
 
    Форма.ИспользоватьСлой(ЗначениеЗакладки, 2);
 
КонецПроцедуры //ПриВыбореЗакладки

Пятнадцатый прием. Сокращение расчетов при отображении текстовых полей. Ярким примером текстового поля содержащего формулу является вывод адреса на форму. Перерисовка и соответственно выполнение формулы происходит при изменении реквизитов формы, при смене закладок. Это обычно не имеет отношения к адресу и поэтому нет смысла вычислять представление адреса. В этом случае можно сделать, например, так. В форме вызов процедуры глобального модуля глПредставлениеАдреса(Адрес) заменить на вызов локальной процедуры ПредставлениеАдреса(), а в модуле формы использовать следующий код:

//*******************************************************
Перем СтАдрес, АдресПредставление;

//*******************************************************
Процедура ПредставлениеАдреса()
 
    Если СтАдрес <> Адрес Тогда
        СтАдрес = Адрес;
        АдресПредставление = глПредставлениеАдреса(СтАдрес);
    КонецЕсли;
 
    Возврат АдресПредставление;
 
КонецПроцедуры
//ПредставлениеАдреса

Формирование представления адреса тоже можно оптимизировать. К теме данной статьи это, наверное, не имеет прямого отношения, но все же. Для формирования представления адреса можно использовать такой код глобального модуля:

//*******************************************************
Перем глСокрАдреса[10];

//*******************************************************
// глПредставлениеАдреса(АдреснаяСтрока,Способ)
//
// Параметры:
//  Адрес (строка), адрес представление которого нужно вернуть.
//  Способ - способ представления адреса (если=1, то возвращает представление адреса без индекса)
//
// Возвращаемое значение:
//  Строка: представление адреса
//
// Описание:
//  Предназначена для формирования адресной строки в "удобочитаемом" виде
//  для отражения в формах.
//
Процедура глПредставлениеАдреса(Адрес, Способ = 0) Экспорт
 
    АдреснаяСтрока = СокрЛП(Адрес);
 
    Если (АдреснаяСтрока = ",,,,,,,,,") или (АдреснаяСтрока = "") Тогда
        Если Способ = 0 Тогда
            Возврат "<>"
        КонецЕсли;
        Возврат ""
    ИначеЕсли СтрЧислоВхождений(АдреснаяСтрока, ",") <> 9 Тогда
        Возврат СтрЗаменить(АдреснаяСтрока, РазделительСтрок, ", ")
    КонецЕсли;

    Индекс = 2;
    Результат = "";
    лСпособ = Способ + 2;
    АдреснаяСтрока = Сред(АдреснаяСтрока, 2);
    Пока АдреснаяСтрока <> "" Цикл
        Если АдреснаяСтрока = "," Тогда
            Прервать
        ИначеЕсли АдреснаяСтрока = ",,," Тогда
            Прервать
        ИначеЕсли АдреснаяСтрока = ",," Тогда
            Прервать
        КонецЕсли; 
 
        Поз = Найти(АдреснаяСтрока, ",");
        Если Поз = 1 Тогда
            АдреснаяСтрока = Сред(АдреснаяСтрока, 2)
        ИначеЕсли Индекс < лСпособ Тогда
            АдреснаяСтрока = Сред(АдреснаяСтрока, Поз + 1)
        Иначе
            Если Поз = 0 Тогда
                СтрокаИзАдреса = АдреснаяСтрока;
                АдреснаяСтрока = ""
            Иначе
                СтрокаИзАдреса = Лев(АдреснаяСтрока, Поз - 1);
                АдреснаяСтрока = Сред(АдреснаяСтрока, Поз + 1)
            КонецЕсли;
   
            Если СтрокаИзАдреса = "" Тогда
            ИначеЕсли Результат = "" Тогда
                Результат = СтрокаИзАдреса
            ИначеЕсли Индекс > 7 Тогда
                Результат = Результат + глСокрАдреса[Индекс] + СтрокаИзАдреса
            Иначе
                Результат = Результат + ", " + СтрокаИзАдреса
            КонецЕсли;
        КонецЕсли;
 
        Индекс = Индекс + 1
    КонецЦикла;

    Возврат Результат

КонецПроцедуры
//глПредставлениеАдреса

//*******************************************************

глСокрАдреса[8] = ", д. ";
глСокрАдреса[9] = ", кор. ";
глСокрАдреса[10] = ", кв. ";

Т.к. адрес встречается во многих местах большинства конфигураций и хранится чаще всего в формате ИМНС, то данная оптимизация может быть весьма полезной.

Шестнадцатый прием. Использование промежуточных (буферных) переменных при сборке строк большой длины. Небольшое усложнение кода (добавляется 5 строк) может дать ускорение в несколько раз. Результат применения шестнадцатого приема можно посмотреть здесь: Дополнительные материалы к статье.

 

Для раскрашивания программного кода в тексте статьи в цвета конфигуратора 1С:Предприятия 7.7 была использована Разукрашка.

31.01.2009 /Константинов Алексей Викторович/
Редакция от 18.02.2011

См. также

Подписаться Добавить вознаграждение
Комментарии
1. ineoosaki (ineoosaki) 31.01.09 23:50
хорошая статья для новичков. +1
Я бы добавил, еще, что при разработке отчетов/печатных форм надо стараться вычислять выражения в модулях, а не в таблицах.
2. Сhe Burashka (CheBurator) 01.02.09 00:34
плюс выигрыш при заполнении областей в печатных вормах
3. Антон Азанов (Djelf) 01.02.09 01:40
А вот если Ускоренное создание объектов в 1С: http://www.1cpp.ru/forum/YaBB.pl?num=1215146216 в функционал turbobl.dll добавить, стало бы еще лучше.
4. Алексей Константинов (alexk-is) 01.02.09 02:02
(3) Зачем? Функционал turbobl.dll полностью присутствует в 1CPP.dll. http://www.1cpp.ru/index.php/VeryBeginning
5. Антон Азанов (Djelf) 01.02.09 02:36
Тут есть некоторая подстава: 1++ конечно содержит весь функционал ускорения, но накладные расходы на дополнительные возможности 1с++ (не все можно отключить) съедают все ускорение. Если мы хотим ускорить штатные функции с минимальным изменением кода turbobl.dll все оказывается значительно лучше 1с++
6. Антон Азанов (Djelf) 01.02.09 02:50
Кстати, вот еще одно ускорение "Быстрые и медленные переменные" http://subscribe.ru/archive/comp.soft.prog.school1c/200501/18080241.html сам не проверял ;)
7. ineoosaki (ineoosaki) 01.02.09 08:07
Функция, заменяющая стандартные методы СоздатьОбъект("ТаблицаЗначений") и СоздатьОбъект("СписокЗначений"), подсмотренная в конфе СКАТ-профессионал, от 33lab:

Функция _Новый(стрОбъект) Экспорт
Если стрОбъект = "СписокЗначений" Тогда
Возврат ЗначениеИзСтрокиВнутр("{""VL"",{}}");
КонецЕсли;
Если стрОбъект = "ТаблицаЗначений" Тогда
Возврат ЗначениеИзСтрокиВнутр("{""VT"",""1"",{""0"",{{"""",""0"",""0"",""0"","""",""2""}}}}");
КонецЕсли;

КонецФункции
8. Артур Аюханов (artbear) 01.02.09 11:29
(5) C чего ты это взял-то про "накладные расходы на доп.возможности 1С++) съедают все ускорение" ? :(
Последние версии 1С++ 3.0.1.ХХ еще сильнее ускоряют 1С даже по сравнению с ТурбоБЛ :)

(7) Кстати, в последних версиях 1С+ 3.0.1.ХХ списки и таблицы значений автоматически создаются намного быстрее, чем в простой 1С, и даже чуть быстрее указанного тобой известного способа :)
9. Артур Аюханов (artbear) 01.02.09 12:00
По поводу печатных форм - еще ускорит формирование применение ранее подготовленных секций.
10. Антон Азанов (Djelf) 01.02.09 13:44
(8) В 1С вообще тесты скорости радуют своей неповторяемостью, поэтому скорость я замерял в ТиС-Демо вот таким образом: обработка перепроводила документы, документы перепроводились несколько раз, либо цепочка документов несколько раз проводилась, в лог попадали min/max/avg.
У меня на этом тесте получилось что максимальная скорость достигается именно с ТурбоБЛ. Если отключить перехватчики в 1C++ скорость повышается, но все равно медленнее чем с ТурбоБЛ.
Проверял я это после введения ускоренного создания объектов в 1С++, честно говоря, был удивлен полученным результатом.
11. Евгений Мартыненков (JohnyDeath) 02.02.09 00:07
Последнее предложение в 10-м приёме (Объединяем ячейки таблицы.) в корне не верно! Чем больше объединённых ячеек, тем медленнее становится таблица. Старайтесь вообще избегать объединений, лучше воспользоваться "по выделенным столбцам"

Ну и про переменные, которые надо сделать глобальными в текущем модуле. Уж не знаю на сколько ты при этом выиграешь в скорости, но вот неожиданных засад ты получаешь тем больше, чем больше у тебя таких переменных.
alyuev; Ёпрст; +2 Ответить 2
12. Евгений Мартыненков (JohnyDeath) 02.02.09 00:12
Автор, ты про главный инструмент забыл - ОТЛАДЧИК с замером ;)
an_2; Valet; +2 Ответить 1
13. Алексей Константинов (alexk-is) 02.02.09 06:52
(11) Отчет на котором я "тренировался" в первоначальном варианте без объединения "съедал" 700 Mb оперативной памяти, а на чем "тренировались" вы?

(12) Ну, это очевидное. Не хотелось бы переписывать документацию...
14. Артур Аюханов (artbear) 02.02.09 07:32
(11) Ага, про глобальные переменные это очень верно :)
(13) Отладчик с замером обязательно нужно упомянуть - без него никуда!

(10) Давай на сайте 1С++ обсудим эту тему?
15. Епрст (Ёпрст) 02.02.09 10:02
10 предложение - гон чистой воды...
Объединенные ячейки - смерть для мокселя... равно как и любые внедренные объекты - картинки, оле-объекты...
16. f13 f13 (f13) 02.02.09 10:10
Собственно автором вопроса про производительность/методы был я.
Спасибо за статью, будет полезна новичкам: недавно натолкнулся на http://infostart.ru/projects/3334/ - после просмотра кода пришел в ужас.

Вопросы вызывают пункты 7 и 11 (как и у всех).

Повсеместное использование глобальных переменных до добра не доводит. Должен быть баланс: иногда логичнее применить способ оптимизации 1 (железа или вообще технология).

Собственно к камням :)
Документ ВводРасчетов модуль документа:

Процедура ОбработкаПроведения(Режим = 0)
// Режим = 0 - провести документ без формирования движений по документу
// Режим = 1 - удалить движения документа
// Режим > 1 - допроведение документа

Если ГрупповаяОбработка() = 1 Тогда
глСообщениеГрупповойОбработки(ТекущийДокумент);
СтатусВозврата(0); Возврат;
ИначеЕсли Режим = 0 Тогда
Возврат;
КонецЕсли;

Если ДатаДок <> НТП Тогда
Предупреждение("Этот документ можно провести только в текущем периоде!");
СтатусВозврата(0); Возврат;
КонецЕсли;

Для Сч = 1 По _гл_СписокАбонентов.РазмерСписка() Цикл
Аб = _гл_СписокАбонентов.ПолучитьЗначение(Сч);
ИнициализацияАбонента();
КонецЦикла;

КонецПроцедуры //ОбработкаПроведения

При интерактивном проведении _гл_СписокАбонентов заполняется. А что будет если мне забожается выполнить ДокВводРасчетов.Провести() из кода обработки?

МНЕ кажется такой подход не оправдан. Не стоит раскидывать логику проведения по разным местам.


17. Алексей Константинов (alexk-is) 02.02.09 10:41
(16) Я думаю что применение любого из предложенных приемов каждый определяет для себя сам. В конфигурациях фирмы 1С часто создается таблица товаров, а затем передается и модифицируется всеми процедурами модуля объекта. Речь собственно шла именно о таких случаях.

По 11 приему вроде не было вопросов. Скоро сделаю обезличенную базу - посмотреть как это выглядит можно будет там.
По 10 приему - можно еще погонять тесты, но варианта без объединения по вертикальным секциям состоящих из нескольких строк я не представляю...

> При интерактивном проведении _гл_СписокАбонентов заполняется. А что будет если мне забожается выполнить ДокВводРасчетов.Провести() из кода обработки?
Внутри конфигурации есть групповая обработка документов. Там все работает как надо...
Сейчас проверю. Добавлю статистику по этому вопросу...
18. f13 f13 (f13) 02.02.09 11:38
(17) конечно же имел ввиду 10 пункт.

Я НЕ сомневаюсь, что работает как надо :).

Речь об "изолированности" что-ли. Ведь можно передавать список в качестве параметра для функции проведения: ОбработкаПроведения(вхСписокАбонентов), и получить более "устойчивый" функционал :)

З.Ы. Сейчас задам вопрос в теме http://infostart.ru/projects/3163
19. Алексей Константинов (alexk-is) 02.02.09 12:46
(18) По пятому приему статистика следующая:
При проведении документа в 1 транзакции время проведения не стабильно в течении сеанса:
1 проведение - 128 секунд
2 проведение - 216 секунд
3 проведение - 235 секунд
4 проведение - 700 секунд
5 проведение - 221 секунда
6 проведение - 668 секунд

При использовании приема время проведения стабильно в течении сеанса - 49 секунд
20. Алексей Константинов (alexk-is) 02.02.09 16:32
+19
В 19 посте данные при работе в монопольном режиме.
В разделенном режиме терминальной сессии картинка иная.

Проведение в 1 транзакции
1 проведение - 756 секунд
2 проведение - 955 секунд
3 проведение - 1080 секунд
4 проведение - 1056 секунд

Проведение с использованием 5 приема - 65 секунд стабильно
21. Антон Азанов (Djelf) 03.02.09 18:45
(14) Извиняюсь, был не прав насчет 1с++. Тест пепероведения базы на рам-диске (чтоб исключить влияние дисковой системы) показал, что с 1с++ база проводится быстрее чем с turbobl.
22. Валентин Терёхин (Valet) 03.02.09 19:17
Присоединяюсь к мнению что начинать надо с замера производительности в отладчике. Иначе часты варианты, что тратим кучу времени на оптимизацию какого то куска, а этот основная проблема в другом месте.
При этом рефакторинг даст существенно меньший прирост.
Сначала выявить узкие места, а потом решать в каком порядке их чинить.
23. Владислав Чинючин (vcv) 03.02.09 19:35
(20) А поясните, пожалуйста, в общих чертах, возможную техническую реализацию 5-го приема.
24. Алексей Константинов (alexk-is) 04.02.09 06:27
(23)
1. Отключается автоматическое удаление движений документа
2. В форме документа создается процедура, которая запускает на проведение документ блоками
3. В модуле документа процедура проведения изменяется на работу с блоками данных
4. В модуле документа добавляется процедура отмены проведения
5. В глобальном модуле добавляются процедуры на события пометки на удаление и отмены проведения документов с "особой" обработкой документов без автоматического удаления движений
6. Изменяется групповая обработка документов, которая для документов без автоматического удаления движений открывает форму с передачей параметра запускающего документ на проведение

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

Примеры реализации можно посмотреть в типовых конфигурациях 1С или здесь http://www.infostart.ru/projects/3163/
25. Алексей Константинов (alexk-is) 04.02.09 08:14
+24 При больших объемах обрабатываемой информации, эффективнее передавать указатель. Т.к. большие списки это дополнительные ресурсы ПК.
26. Артур Аюханов (artbear) 04.02.09 10:18
27. Михаил Семенов (Shaman100M) 04.02.09 18:25
(0) К теме можно добавить библиотеку Vk_TerminalSleep. от Ромикса http://infostart.ru/projects/1515/
28. Владимир (hogik) 04.02.09 20:53
(0)(alexk-is)
Вопрос по "Пятый прием". Как можно "при использовании данного приема документ проводится несколькими транзакциями"? Не понимаю... :-(
29. nickVZ (nickVZ) 04.02.09 20:55
Во-первых, насчет "современной вычислительной системы". Это понятие ("вычислительная система") включает в себя и "железо" и "софт". Так вот, современный "софт" может сущестенно "затормозить" исполнение Предприятия 7.7. Классика жанра: клиент на w98 работает значительно быстрее, чем клиент на XP :) Настройкой эту разницу можно превратить в "слегка быстрее", но ликвидировать невозможно.
А про настройки сервера базы в статейке ни слова....
Зато немало места уделено тому, чему вообще не надо уделять внимания в теме "производительность". Какое-такое снижение производительности вы добъетесь манипуляцией объявления закладок формы?! Вы о чем? Отладка чего-то в формах совершенно бессмыслена, если результат "не заметен глазу".
Как приятно было узнать (из ссылка на subscribe.ru), что обращения к реквизитам формы "самые медленные". Только надо циклом обратиться к ним миллион раз, чтоб заметить это :))

Но для сдачи зачета пойдет ;)
30. nickVZ (nickVZ) 04.02.09 21:13
И еще... Не знаю что - смеятся или плакать от совета "вынести за циклы" команды СоздатьОбъект"....
Это совершенно не имеет отношения к "1С:Предприятие". Требование "выноси за пределы цикла все, что можно сделать вне цикла" - это ШКОЛА. И дОлжно исполнятся не думая.
31. Алексей Константинов (alexk-is) 05.02.09 01:59
(28) Расписал подробнее. Стало понятнее?
32. Алексей Константинов (alexk-is) 05.02.09 02:28
(30) Открываю в ЗиК 7.70.284 форму элемента справочника сотрудники. В процедуре Печать18ФО ищем СоздатьОбъект("СписокЗначений").
Документ ЗаявкаНаОткрытиеСчетов процедура СформироватьФайлНаОткрытиеСчетов ищем СоздатьОбъект("Справочник.ДокументыУдостоверяющиеЛичность").
Документ НачислениеНалоговСФОТ процедура ПровестиИзФормы ищем СоздатьОбъект("СписокЗначений").
Документ ПриказНаОплатуПоСреднему процедура Печать ищем СоздатьОбъект("ТаблицаЗначений").
...нашел еще 5 мест - надоело...
Теперь можно смеяться или плакать...
33. Алексей Константинов (alexk-is) 05.02.09 02:43
(29) Статья про программу Абонентский отдел водоканала. Про программу, а не про сервер. Сервер это тоже важно, но к программированию не имеет прямого отношения...

Замените закладки на Перечисление или Константы. Собственно примеров можно придумать много...
Вот из той же ЗиК

Функция глСЗВПеречислениеСтароеВНовое(Старое) Экспорт
//Если Старое.Вид() = "СЗВОсобыеУсловияТруда" Тогда
Если Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12А Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п1;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Б Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п2;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12В Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п3;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Г Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п4;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Д Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п5;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Е Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п6;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Ж Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п7;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12З Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п8;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12И Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п9;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12К Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст27п10;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12Л Тогда
Старое = ПолучитьПустоеЗначение("Перечисление.СЗВОсобыеУсловияТруда2002");
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12М Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст28пОС;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.ЗП12О Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст28пПЖ;
ИначеЕсли Старое = Перечисление.СЗВОсобыеУсловияТруда.СЕВ26 Тогда
Старое = Перечисление.СЗВОсобыеУсловияТруда2002.ст28пСЕВ;
//ИначеЕсли Старое.Вид() = "СЗВОснованияИТС" Тогда
ИначеЕсли Старое = Перечисление.СЗВОснованияИТС.СЕЗОН Тогда
Старое = Перечисление.СЗВОснованияИТС2002.СЕЗОН;
ИначеЕсли Старое = Перечисление.СЗВОснованияИТС.ЛЕПРО Тогда
Старое = ПолучитьПустоеЗначение("Перечисление.СЗВОснованияИТС2002");
ИначеЕсли Старое = Перечисление.СЗВОснованияИТС.УИК104 Тогда
Старое = Перечисление.СЗВОснованияИТС2002.УИК104;
ИначеЕсли Старое = Перечисление.СЗВОснованияИТС.ВОДОЛАЗ Тогда
Старое = Перечисление.СЗВОснованияИТС2002.ВОДОЛАЗ;
//ИначеЕсли Старое.Вид() = "СЗВОснованияВыслугиЛет" Тогда
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП78ГР Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п11ГР;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП78ВП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п11ВП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП78ФЛ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п12;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП78СС Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП80ПД Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пПД;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП80РК Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пПДРК;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП81ГД Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пГД;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЗП81СМ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пСМ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ХИРУРГД Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пГДХР;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ХИРУРСМ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст28пСМХР;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ТВОРЧ15 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ТВОРЧ15;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ТВОРЧ20 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ТВОРЧ20;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ТВОРЧ25 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ТВОРЧ25;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ТВОРЧ30 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ТВОРЧ30;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.САМОЛЕТ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.САМОЛЕТ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.СПЕЦАВ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.СПЕЦАВ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.СПАСАВ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.СПАСАВ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.УЧЛЕТ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.УЧЛЕТ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ВЫСШПИЛ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ВЫСШПИЛ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.НОРМАПР Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.НОРМАПР;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.НОРМСП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.НОРМСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.РЕАКТИВН Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.НОРМСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЛЕТРАБ Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ЛЕТРАБ;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ЛЕТИСП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ЛЕТИСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ОПЫТИСП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ОПЫТИСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ИСПКЛС1 Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ИСПКЛС1;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ИТСИСП Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ИТСИСП;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.УВД Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п14;
ИначеЕсли Старое = Перечисление.СЗВОснованияВыслугиЛет.ИТС Тогда
Старое = Перечисление.СЗВОснованияВыслугиЛет2002.ст27п15;
КонецЕсли;

Возврат Старое;

КонецФункции // глСЗВПеречислениеСтароеВНовое()


или вот еще


Процедура глСброситьПрогрессор(Прогрессор) Экспорт
Прогрессор.ПолучитьЗначение(2).Прогрессор.Заголовок("");
Прогрессор.ПолучитьЗначение(2).ПроцентПрогрессора.Заголовок(Формат(0,"Ч3")+"%");
Прогрессор.ПолучитьЗначение(2).Обновить(0);
Прогрессор.УстановитьЗначение(1,0);
КонецПроцедуры // глСброситьПрогрессор
34. Владимир (hogik) 05.02.09 03:25
(31)(alexk-is)
Да, стало понятнее. Спасибо. Но мне суть алгоритма не понравилась...
35. Алексей Константинов (alexk-is) 05.02.09 03:44
36. Владимир (hogik) 05.02.09 03:59
(35)(alexk-is)
Почему? А Вы это написали во втором абзаце "пятого приёма". Плюс приличные переделки конфигурации. Однако проблема больших транзакций в DBFной 1С существует. Я, как раз, недавно проводил тестирование этой проблемы. Так если выполняется 10'000 некоторых (моего теста) обновлений в рамках одной транзакции, то это занимает пол минуты. А для 100'000 таких же действий - часы. Т.е. это дольше не в 10 раз :-(. В этом смысле CodeBase - бяка... ;-)
37. Алексей Константинов (alexk-is) 05.02.09 04:41
(36) Да, есть такая закономерность, что чем больше объектов в транзакции, тем медленее она выполняется. Поэтому и появились эффективные порции. В первоначальном варианте документ проводился несколько часов, а потом расчитывался еще несколько часов. Для фронт-офисной программы это непростительная роскошь, т.к. всегда стоит очередь...

Так такой выход из ситуации? Какие предложения?
38. Владимир (hogik) 05.02.09 05:35
(37)(alexk-is)
"Так такой выход из ситуации?"
Сменить СУБД.
"Какие предложения?"
Если оставлять Ваш алгоритм, то хотя бы упразднить большие переделки конфигурации. Например, взять вот эту дрянь http://infostart.ru/projects/2418/ и добавить управляемый алгоритм принудительного завершения и начала реальной транзакции внутри логической транзакции. С помощью вызова некой функции, расставленной в тексте конфигуратора. И еще добавить алгоритм отслеживания целостности...
39. Владимир (hogik) 05.02.09 05:44
(37)(alexk-is)
+(38) И сразу вопрос себе - а как откат транзакции делать? А у Вас как это делается?
40. Алексей Константинов (alexk-is) 05.02.09 06:44
Удаление движений документа:

Если глУдалитьДвиженияДокумента(ТекущийДокумент()) = 0 Тогда
Возврат
КонецЕсли;
41. Епрст (Ёпрст) 05.02.09 07:00
(40) А есть уверенность что они удаляться ?
42. Епрст (Ёпрст) 05.02.09 07:02
+41 тем более,что цикл просто прерывается...
43. Алексей Константинов (alexk-is) 05.02.09 07:15
Пока не спрашивали проблем не было. Теперь наверное будут... :)
44. Епрст (Ёпрст) 05.02.09 07:25
(43) Таи вообще в топике - не рабочий алгоритм...
На N-ой строке не провелось по какой-либо причине (транзакция например, или тупо по условию в модуле проведения, не суть важно как) и привет...Документик на половину проведён ? ...
45. Епрст (Ёпрст) 05.02.09 07:27
Я понимаю еще, когда делают весь расчет ммодуле формы, а в ОбработкаПроведения пишут только готовые движения... только потеря актуальности данных может быть в таком случае...
А тут - в данном виде вообще каша :)
46. Епрст (Ёпрст) 05.02.09 07:29
Еще каша будет, при любом аварийном выходе при проведении такого документа..
Часть движений уже будет в ИБ.
47. nickVZ (nickVZ) 05.02.09 11:47
(32) "...нашел еще 5 мест - надоело...". Дык дело-то не в ЗиК. Обсуждается статья. Которая, несомненно, привлечет внимание многих своим заголовком.
Сырая статья. Ну очень сырая. Поспешил ты. Написал то, что не стОило упоминания. Скомкал то, что достойно более тщательного описания (про "пятый пункт", например).
Вот что обидно.

А приведенные тобой примеры вполне ложаться в раздел "Программируйте правильно". Или "Как не надо кодить". А что? Стиль оказывает общеоздоровляющее действие и на производительность ;))

Хотелось бы поместить статью в свой директорий на диске "Полезные статьи", ан не судьба. Вот такое эгоистическое желание.
Но еще не вечер? Да? :)
48. Владимир (hogik) 05.02.09 16:48
(40)(alexk-is)
"Удаление движений документа:..."
Согласен с Ёпрст в (41-46). И сомневаюсь, что "...проблем за 8 лет не возникало"©. Или всем всё безразлично при работе с Вашей разработкой... Или, типа, как в анекдоте: "Нам выдают бесплатное молоко, т.к. у нас вредное производство. Но мы этого не замечаем, не замечаем, не замечаем...".
49. Алексей Константинов (alexk-is) 08.02.09 18:25
(7) Провел испытания. По предложенной схеме. Этот интересный вариант оказался более медленным даже без вызова функции.

Результаты проверки:
Список значений: 1: 410 2: 427
Таблица значений: 1: 498 2: 1254

Текст процедуры проверки:
//*******************************************
Процедура Сформировать()
С1 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = глТипСписокЗначений();
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VL"",{}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Сообщить("Список значений: 1: " + (С2 - С1) + " 2: " + (С3 - С2));
С1 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = глТипТаблицаЗначений();
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VT"",""1"",{""0"",{{"""",""0"",""0"",""0"","""",""2""}}}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Сообщить("Таблица значений: 1: " + (С2 - С1) + " 2: " + (С3 - С2));
КонецПроцедуры
50. Алексей Константинов (alexk-is) 08.02.09 18:46
+49 Поменял немного тест. Я в шоке...

Текст процедуры проверки:
//*******************************************
Процедура Сформировать()
С1 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = глТипСписокЗначений();
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VL"",{}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = СоздатьОбъект("СписокЗначений");
КонецЦикла;
С4 = _GetPerformanceCounter();
Сообщить("Список значений: 1: " + (С2 - С1) + " 2: " + (С3 - С2) + " 3: " + (С4 - С3));
С1 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = глТипТаблицаЗначений();
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VT"",""1"",{""0"",{{"""",""0"",""0"",""0"","""",""2""}}}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = СоздатьОбъект("ТаблицаЗначений");
КонецЦикла;
С4 = _GetPerformanceCounter();
Сообщить("Таблица значений 1: " + (С2 - С1) + " 2: " + (С3 - С2) + " 3: " + (С4 - С3));
КонецПроцедуры

Результаты проверки:

Без библиотек
Список значений: 1: 1405 2: 441 3: 5275
Таблица значений 1: 1693 2: 1246 3: 6356

Загружена turbo.bl
Список значений: 1: 396 2: 422 3: 5242
Таблица значений 1: 490 2: 1229 3: 6349

Загружена 1cpp.dll
Список значений: 1: 405 2: 427 3: 202
Таблица значений 1: 496 2: 1262 3: 253
51. Юрий Тимофеев (Tatitutu) 10.02.09 14:03
"Шестой прием связан с заменой использования для объектов типа СписокЗначений метода Принадлежит() на метод Найти()."

может все таки не Найти() , а НайтиЗначение()?
52. Алексей Константинов (alexk-is) 10.02.09 14:29
53. Артур Аюханов (artbear) 10.02.09 15:16
(50) Надеюсь, теперь вопросы по необходимости юзания 1С++ сняты? :)

ЗЫ ведь и другие встроенные объекты ускорены :) а не только СЗ и ТЗ.
54. Алексей Константинов (alexk-is) 10.02.09 16:09
(53) Я думаю, что в типовых конфигурациях лидерство однозначно будет за 1С++.

Переписал тест. Убрал время на цикл. Поставил прямые вызовы.

Текст процедуры проверки:
//*******************************************
Процедура Сформировать()
Перем А, ПустойСписокЗначений, ПустаяТаблицаЗначений;
С0 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
КонецЦикла;
С1 = _GetPerformanceCounter();
глПустойСписокЗначений.Выгрузить(ПустойСписокЗначений);
Для Индекс = 1 По 100000 Цикл
ПустойСписокЗначений.Выгрузить(А);
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VL"",{}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = СоздатьОбъект("СписокЗначений");
КонецЦикла;
С4 = _GetPerformanceCounter();
ПоправкаНаЦикл = С1 - С0;
Сообщить("Список значений: 1: " + (С2 - С1 - ПоправкаНаЦикл) + " 2: " + (С3 - С2 - ПоправкаНаЦикл) + " 3: " + (С4 - С3 - ПоправкаНаЦикл));
С1 = _GetPerformanceCounter();
глПустаяТаблицаЗначений.Выгрузить(ПустаяТаблицаЗначений);
Для Индекс = 1 По 100000 Цикл
ПустаяТаблицаЗначений.Выгрузить(А);
КонецЦикла;
С2 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = ЗначениеИзСтрокиВнутр("{""VT"",""1"",{""0"",{{"""",""0"",""0"",""0"","""",""2""}}}}");
КонецЦикла;
С3 = _GetPerformanceCounter();
Для Индекс = 1 По 100000 Цикл
А = СоздатьОбъект("ТаблицаЗначений");
КонецЦикла;
С4 = _GetPerformanceCounter();
Сообщить("Таблица значений 1: " + (С2 - С1 - ПоправкаНаЦикл) + " 2: " + (С3 - С2 - ПоправкаНаЦикл) + " 3: " + (С4 - С3 - ПоправкаНаЦикл));
КонецПроцедуры


Результаты проверки:

Без библиотек
Список значений: 1: 1031 2: 352 3: 5204
Таблица значений 1: 1249 2: 1167 3: 6303

Загружена turbo.bl
Список значений: 1: 98 2: 348 3: 5178
Таблица значений 1: 116 2: 1143 3: 6279

Загружена 1cpp.dll
Список значений: 1: 101 2: 351 3: 131
Таблица значений 1: 118 2: 1142 3: 181
55. Епрст (Ёпрст) 10.02.09 16:41
Итого в сухом остатке
1. Загрузка ВК +
2.сокращением общего количества точек -
3.Сокращение вызовов СоздатьОбъект -
4. ?? Вообще не понятно о какой оптимизации идёт речь
5.спользованием эффективных порций -
6.Использовать НайтиЗначение вместо Принадлежит +/-
если СЗ статичный, то Принадлежит быстрее...причем намного
7.объявить переменными модуля не есть гуд -
8.Непонятно о каком повторном чтении данных идёт речь .. +
9.Выражения расчитывать вне мокселя +
10. Объединять ячейки -
(и вообще, стараться избегать их вообще, даже если страдает красота при объединении вертикальных ячеек)
11.Вы предлагаете смотреть отчет в 5-6 листах что ли ? Кто его вообще смотреть будет ?
-
12.Печать без просмотра +

Итого:

4 +
6 -

:)
Получается "оптимизация" наоборот...
56. Алексей Константинов (alexk-is) 10.02.09 18:55
(55) Бодаться можно вечно. Подготовлю тесты и контрольные примеры...
Не уверен что быстро, но пока готовы только 2 синтетических теста...
57. Епрст (Ёпрст) 11.02.09 09:00
(56) Никто и не бодается.. просто итог статьи.
58. Александр Рытов (Арчибальд) 11.02.09 13:08
Что-то обсуждение чисто техническое. Что будет работать, что не будет. Послушаем автора:
1) Статья про абонентский отдел водоканала.
2) Фронт офис.
3) Компонента "Расчет".

Уже некий сюрреализм. Еще бы торговый зал супермаркета на журнале расчетов построили.
Похоже, дело было так. Пришел лох, попросил инструмент для закручивания шурупов, ему впарили титановый абак с заточенным углом. Мало ли, что отверток нет, лоха упускать нельзя!
Потом оказалось, что шурупов много, и расположены они близко друг к другу, а абак громоздкий. Нет проблем, пилим его на части. И чтоб не гремел, камешки вытряхиваем - за отдельную плату, конечно.

4) Перерасчет за пол года формирует 190000 записей за 2 минуты, при этом проводится только 1 документ.

190000 записей из одного документа, не уголовщина, конечно, но оскорбление общестенной нравственности - однозначно. Если вы едете в автомобиле по городу с нормальной скоростью, но на двух колесах, ПДД вы не нарушаете. Но на первом же посту вас тормознут - и правильно сделают.
Кстати, а зачем может потребоваться перерасчет сразу всех за полгода? При изменении законодалельства задним числом? Это уже форс-мажор, имхо. А если полгода назад абонент заплатил 200 рублей, а разнесли ему 20, так при нормальной реализации требуется одна запись, а не 180000.
59. Алексей Константинов (alexk-is) 11.02.09 18:10
(58) Я так понимаю разговор идет об альтернативном решении на 7.7. Хорошо давай посмотрим его...
60. Алексей Константинов (alexk-is) 11.02.09 18:17
...странный получается разговор...
- есть заводик. делает розетки
- да? какие?
- вот смотрите. все здесь
- что всего 12? такое мы богато бачили. лучше бы сало показали
- да нет. он много может делать. это образцы - 12 цветов
- много может делать? а что, есть проблемы с производительностью? как вы их решаете
- сокращаем непроизводственные потери
- потери уже потеряны. итог "ацтой"
- но он ведь может делать 190000 шт. за 2 минуты
- зачем делать 190000, когда можно делать только 1?
- ...
61. darkfire (darkfire) 11.02.09 18:57
Ни кто не спорит все круто и классно когда ты можешь перепахать конфу вдоль и поперек, но, если тебе надо внести минимум изменений чтоб оставаться максимально близко к типовой или ты вообще работаешь с базовой версией или над одной конфой работает человек десять и каждый вносит свои изменения по требованиям пользователей, т.е. в пожарном порядке охватить мыслью все что на работали до тебя и выдать оптимальное не конфликтное решение =)
Вобщем решения интересны, но не всегда реализуемы
62. Алексей Константинов (alexk-is) 12.02.09 12:15
63. Алексей Константинов (alexk-is) 14.02.09 11:01
(61) Для базовой версии можно воспользоваться 1 приемом. Например, перед расчетом зарплаты или другой ресурсоемкой операцией запустить обработку, которая загрузит библиотеки.

Когда конфигурация самописная, то все понятно - режешь как хочешь. В типовых конфигурациях мне приходилось оптимизоровать лишь самые узкие места с точки зрения пользователей. Т.е. внося минимальные изменения в конфигурацию, но получая максимальный эффект.
64. Александр Рытов (Арчибальд) 16.02.09 10:08
(59)http://www.kamin.kaluga.ru/products/rent/
Это не готовое решение, конечно, но пример реализации на компоненте Бухучет.
Речь шла о том, что содержательных расчетов для нескольких тысяч абонентских точек не требуется – начисление фиксированное. Содержательные расчеты, вроде перемножения двух чисел требуются при изменении статуса абонентской точки (справку принесли), при поступлении платежа – это две-три проводки. При вводе показаний счетчиков контролерами количество проводок соответствует количеству строк документа. Все это измеряется в секундах.
Вот начисление по бессчетчиковым абонентским точкам в случае, когда их десятки тысяч, требует оптимизации. Например, разделить получение (периодической) начисляемой суммы по абонентским точкам (заполнение непериодического реквизита «ТекущийПлатеж») и формирование проводок.
65. Алексей Константинов (alexk-is) 16.02.09 12:48
(64) Итак, начисление по бессчетчиковым абонентским точкам - требует оптимизации.
А статья как раз об оптимизации...

В конфигурации "Абонентский отдел водоканала", например, ПКО рассчитан на работу с 1 абонентом. Но есть ряд документов рассчитанных на работу с несколькими тысячами абонентов. И приведенный в заголовке пример как раз обсчитывает абонентов, услуги для которых рассчитываются по нормам.
66. Александр Рытов (Арчибальд) 16.02.09 13:33
(65) Я отнюдь не против обсуждения приемов оптимизации. Минуса я ведь не поставил.
Мои замечания касались применения в конкретной предметной области неподходящего инструмента.
Вот, например, "Но есть ряд документов рассчитанных на работу с несколькими тысячами абонентов".
Эти документы не существуют сами по себе. Они придуманы разработчиком конфигурации. Из потребностей автоматизации они не вытекают. И уж точно, когда клиент пришел выяснить состояние взаиморасчетов, оператор не должен перелопачивать записи в БД, к данному клиенту не относящиеся.
67. Александр Рытов (Арчибальд) 16.02.09 13:49
+66 "В первоначальном варианте документ проводился несколько часов, а потом расчитывался еще несколько часов. Для фронт-офисной программы это непростительная роскошь, т.к. всегда стоит очередь..."
Вполне очевидно, что это непростительная роскошь => такой документ не нужен.
68. Алексей Константинов (alexk-is) 16.02.09 19:10
(67) Предлагаю обсуждение самой программы перенести сюда http://www.infostart.ru/projects/3163
69. Алексей Константинов (alexk-is) 17.02.09 22:41
(47) (55) Поправил статью, добавил тесты. Лучше стало?
70. Артур Аюханов (artbear) 18.02.09 08:08
ИМХО по первому приему давно очевидно, что последние версии 1С++ - 3.0.1.ХХ еще лучше ускоряют всю систему, чем ТурбоБЛ :)
71. Алексей Константинов (alexk-is) 18.02.09 12:19
(70) Как было написано в 54 посте, в типовых конфигурациях лидерство однозначно будет за 1cpp.dll.

Но в некоторых отдельных случаях turbo.bl может быть эффективннее. См. результаты проверки в 54 посте. Думаю это зависит от конкретной конфигурации и от конкретного комьютера. Например, если есть проблемы с загрузкой 1cpp.dll, то можно использовать turbo.bl. Это будет лучше чем не использовать ничего...
72. bulpi bulpi (bulpi) 06.05.09 16:44
Все это очень умнО (кроме шуток) А слабО писАть такие конфигурации, при использовании которых даже не возникает мысли об оптимизации, т.к. оптимизация на этапе постановки задачи и разработки алгоритмов на 2 порядка перекрывает потери в миллисекундах от использования СоздатьОбъект ?
vkr; Арчибальд; +2 Ответить 1
73. Алексей Константинов (alexk-is) 06.05.09 16:56
(72) Так статья про такую конфигурацию :)
Все описанные приемы были заложены при разработке конфигурации и не описанные тоже :)
74. Степан (stepan_shock) 09.06.09 10:39
Вы можете реально что нибуть посоветовать в таком случае: 2 ПК, на одном компе лежит 1С7.7 БУХ. База 1,5 гига. Второй комп подключается по сети, при этом интерфейс тормозит безбожно, то есть для того, чтобы тупо набить номенклатуру в накладную при выборе из справочника уходит много времени.
Естественно на том коме, где лежит база все быстро.
Конфигурация компов 1ПК: CoreDuo, 1Gb RAM, GigabitLAN , 2ПК: CeleronD, 512 Mb RAM , GigabitLAN/
Выключение Кашмарского эффекта не дает:(
75. Епрст (Ёпрст) 09.06.09 10:51
(74) поднять сервер терминалов...или скуль, или альтернатива на кодебэйсе или адвантадже..
76. Степан (stepan_shock) 09.06.09 10:55
ребята о чем вы говорите, "поднять терминал для двух компов" , поставить "скуль" стоимость бюджета проекта превысит годовую зарплату буха:))
77. Епрст (Ёпрст) 09.06.09 11:56
(76) не вопрос.. найди админа ставь нетварь и работай.
78. Степан (stepan_shock) 09.06.09 12:05
:) я админ. у юзера стоит Лиценз. хрюша и другого ставить незя
79. Алексей Константинов (alexk-is) 09.06.09 12:12
(74) К уже предложенным в (75) вариантам и к приемам изложенным в статье добавлю:
1. можно уменьшить трафик по сети отключив неиспользуемые отборы и сортировки по операциям и проводкам
2. можно уменьшить трафик по сети увеличив время обновления списков
3. проверить работу антивирусов, отключить проверку сетевых дисков
4. проверить размещение каталогов пользователей, сделать каталоги локальными
5. почистить файл с настройками пользователей 1Cv7.CFG
6. можно уменьшить время обработки, сделать upgrade слабого компьютера
7. проверить работу сети. влючен ли Gigabit FullDuplex. какая скорость прокачки?
8. выполнить дефрагментацию жестких дисков обоих ПК
80. Епрст (Ёпрст) 09.06.09 12:28
(78) а при чем тут юзверь вообще ? На сервак ставь..
81. Степан (stepan_shock) 09.06.09 12:35
ну нету отдельного компь.тера... нету!!! и никто не купит для ДВОИХ бухов СЕРВЕР (((
82. Епрст (Ёпрст) 09.06.09 12:39
83. Степан (stepan_shock) 09.06.09 12:49
84. Епрст (Ёпрст) 09.06.09 12:53
(83) можешь из хрюши своей сделать терминал-сервер.. но не помню, лицю. при этом теряется, или нет ?
И второй чорт будет работать по удаленке как на сервере терминалов..
памяти еще доставишь в первый комп..
85. Епрст (Ёпрст) 09.06.09 12:54
+84 как на хрюше сделать сервер терминалов - в поиск..
86. Епрст (Ёпрст) 09.06.09 12:56
http://martin-martin.narod.ru/xpterminal.html
так, например и еще до едрени фени ссылок...
87. Альтаир (Altair777) 17.09.09 14:46
(0)
В пятом приеме нужно поправить ссылку http://www.infostart.ru/projects/3163/
88. Альтаир (Altair777) 17.09.09 14:47
+(87) Везде. Почти все ссылки неправильные.
89. Алексей Константинов (alexk-is) 20.10.09 09:09
90. Альтаир (Altair777) 20.10.09 10:57
(89) А приемчиков не добавилось?
91. Алексей Константинов (alexk-is) 20.10.09 13:58
92. Артур Аюханов (artbear) 28.01.10 15:43
В последних версиях 1С++ З.Х достигнуто максимальное уменьшение времени создания любых объектов в 1С 77 даже в сравнении с более ранними версиями 1С++ 2.Х и З.Х

Простая загрузка 1С++ уже серьезно ускоряет систему.
93. Алексей Константинов (alexk-is) 28.01.10 16:17
(92) Да. Знаю. Скачал. Проверил. С 1С++ З.Х работает быстрее.
Но прием описанный в статье после загрузки 1С++ З.Х выполняется все равно быстрее, чем создание нового объекта. Это наглядно демонстрирует тест приема 3. Вот лог теста:

Список значений: 1 (из статьи): 1078 2 (альтернативный): 347 3 (типовой): 74725
Ускорение (из статьи): 69.32
Ускорение (альтернативный): 215.35
Прием 3 из статьи "1С:Предприятие 7.7. Оптимизация."
Таблица значений 1 (из статьи): 1252 2 (альтернативный): 1146 3 (типовой): 75911
Ускорение (из статьи): 60.63
Ускорение (альтернативный): 66.24

1cpp.dll загружена

Список значений: 1 (из статьи): 100 2 (альтернативный): 356 3 (типовой): 128
Ускорение (из статьи): 1.28
Ускорение (альтернативный): 0.36
Прием 3 из статьи "1С:Предприятие 7.7. Оптимизация."
Таблица значений 1 (из статьи): 118 2 (альтернативный): 1201 3 (типовой): 188
Ускорение (из статьи): 1.59
Ускорение (альтернативный): 0.16
94. Артур Аюханов (artbear) 28.01.10 16:42
(93) Прикольно, т.к. по СЗ точно знаю, что при загруженной 1С++ внутри 1С юзается почти полный аналог создания СЗ из строки - сам его писал в коде 1С++ :)
95. Алексей Константинов (alexk-is) 28.01.10 16:50
(94) Может нужно было сделать по аналогии со статьей? При загрузке библиотеки создать пустые СписокЗначений и ТаблицаЗначений, а потом получать их копии. Тогда бы предложенный мной в статье вариант проиграл бы, наверное...

Тогда я статью поправлю...
96. Артур Аюханов (artbear) 28.01.10 17:22
(95) Я именно так и делал для СЗ и ТЗ :)
Возможно, уже после меня kms переписал на более универсальный способ, который не так хорош для СЗ и ТЗ.
97. Алексей Константинов (alexk-is) 25.03.10 17:05
Если есть вопросы по поводу продажи "Система электронного документооборота 'Управление делами' : 1 лицензия", то работы по преодолению несоответствий ведутся. И я искренне надеюсь, что ситуация в ближайшее время благополучно разрешиться.
98. Алексей Константинов (alexk-is) 26.03.10 21:35
Результат применения 9, 10, 11 приемов можно посмотреть здесь http://www.infostart.ru/public/67695/
99. ehoo ehoo (ehoo) 07.04.10 09:19
Большое спасибо за статью. О некоторых приемах даже не догадывалась.