Сам вопрос возник из размышлений: «Что лучше: использовать общий код в модуле объекта для управляемых и неуправляемых формах или все-таки дублировать код для разных форм?» Путем гугления наткнулся на вот эту статью по сабжу, но к сожалению, в в ней вопрос прозводительности не затрагивался.
Итак, я подготовил код и приступил к замерам производительности. Т.к. меня интересует только дополнительные затраты времени на преобразование данных функциями РеквизитФормыВЗначение -> ЗначениеВРеквизитФормы тестовая операция будет простой: изменение текста комментария документа конкатенированием на каждой итерации строки «1». Для тестрования используется самописный документ Квотация. В документе около 40 реквизитов и присутствует ТЧ Товары, но в тестовом документе заполнена всего лишь 1 строка, т.е. объем данных самого тестового документа относительно небольшой. Для каждого варианта кода выполняется 100 итераций. Замер выполняется для тонкого клиента в рамках локальной сети. При работе через браузер картинка для конечного пользователя скорее всего получится более печальной.
Тест 1. 100 вызовов на сервере
// в модуле объекта документа
Процедура РасширитьКомментарий() Экспорт
Комментарий = Комментарий + "1";
КонецПроцедуры
// в модуле управляемой формы
&НаСервере
Процедура РасширитьКомментарий()
Объект.Комментарий = Объект.Комментарий + "1";
КонецПроцедуры
&НаСервере
Процедура ТестВМодульФормыНаСервере()
Объект.Комментарий = "";
Для Инд = 0 По 99 Цикл
РасширитьКомментарий();
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ТестВМодульФормы(Команда)
ТестВМодульФормыНаСервере();
ПоказатьПредупреждение(, "Завершено!");
КонецПроцедуры
&НаСервере
Процедура ТестВМодульОбъектаНаСервере()
Объект.Комментарий = "";
Для Инд = 0 По 99 Цикл
Документ = РеквизитФормыВЗначение("Объект", Тип("ДокументОбъект.Квотация"));
Документ.РасширитьКомментарий();
ЗначениеВРеквизитФормы(Документ, "Объект");
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ТестВМодульОбъекта(Команда)
ТестВМодульОбъектаНаСервере();
ПоказатьПредупреждение(, "Завершено!");
КонецПроцедуры
Замер производительности показал
Строка |
Кол-во |
Время |
% Врем |
ТестВМодульОбъектаНаСервере(); |
1 |
0.940744 |
89.09 |
Документ = РеквизитФормыВЗначение(«Объект», Тип(«ДокументОбъект.Квотация»)); |
100 |
0.741111 |
70.18 |
ТестВМодульФормыНаСервере(); |
1 |
0.082241 |
7.79 |
ЗначениеВРеквизитФормы(Документ, «Объект»); |
100 |
0.077764 |
7.36 |
ПоказатьПредупреждение(, «Завершено!»); |
1 |
0.026787 |
2.54 |
ПоказатьПредупреждение(, «Завершено!»); |
1 |
0.006109 |
0.58 |
Документ.РасширитьКомментарий(); |
100 |
0.002946 |
0.28 |
РасширитьКомментарий(); |
100 |
0.001812 |
0.17 |
Объект.Комментарий = Объект.Комментарий + «1»; |
100 |
0.000912 |
0.09 |
Комментарий = Комментарий + «1»; |
100 |
0.000880 |
0.08 |
КонецЦикла; |
100 |
0.000409 |
0.04 |
* здесь и далее в таблицах замеров приведена лишь шапка замера. Затраты менее 0.01 с. обрезаны
Тест 2. 100 вызовов сервера
// в модуле объекта документа
Процедура РасширитьКомментарий() Экспорт
Комментарий = Комментарий + "1";
КонецПроцедуры
// в модуле управляемой формы
&НаСервере
Процедура РасширитьКомментарий()
Объект.Комментарий = Объект.Комментарий + "1";
КонецПроцедуры
&НаСервере
Процедура ТестВМодульФормыНаСервере()
РасширитьКомментарий();
КонецПроцедуры
&НаКлиенте
Процедура ТестВМодульФормы(Команда)
Объект.Комментарий = "";
Для Инд = 0 По 99 Цикл
ТестВМодульФормыНаСервере();
КонецЦикла;
ПоказатьПредупреждение(, "Завершено!");
КонецПроцедуры
&НаСервере
Процедура ТестВМодульОбъектаНаСервере()
Документ = РеквизитФормыВЗначение("Объект", Тип("ДокументОбъект.Квотация"));
Документ.РасширитьКомментарий();
ЗначениеВРеквизитФормы(Документ, "Объект");
КонецПроцедуры
&НаКлиенте
Процедура ТестВМодульОбъекта(Команда)
Объект.Комментарий = "";
Для Инд = 0 По 99 Цикл
ТестВМодульОбъектаНаСервере();
КонецЦикла;
ПоказатьПредупреждение(, "Завершено!");
КонецПроцедуры
Замер производительности показал
Строка |
Кол-во |
Время |
% Врем |
ТестВМодульОбъектаНаСервере(); |
100 |
7.786877 |
52.38 |
ТестВМодульФормыНаСервере(); |
100 |
6.145152 |
41.33 |
Документ = РеквизитФормыВЗначение(«Объект», Тип(«ДокументОбъект.Квотация»)); |
100 |
0.998177 |
6.71 |
КонецЦикла; |
100 |
0.502597 |
3.38 |
КонецЦикла; |
100 |
0.401119 |
2.70 |
ЗначениеВРеквизитФормы(Документ, «Объект»); |
100 |
0.090248 |
0.61 |
ТекущийРежим = СоединенияИБ.ПараметрыБлокировкиСеансов(); |
1 |
0.014858 |
0.10 |
ПоказатьПредупреждение(, «Завершено!»); |
1 |
0.009055 |
0.06 |
ПоказатьПредупреждение(, «Завершено!»); |
1 |
0.006647 |
0.04 |
РасширитьКомментарий(); |
100 |
0.003752 |
0.03 |
Документ.РасширитьКомментарий(); |
100 |
0.003544 |
0.02 |
Объект.Комментарий = Объект.Комментарий + «1»; |
100 |
0.002546 |
0.02 |
Комментарий = Комментарий + «1»; |
100 |
0.001131 |
0.01 |
Т.е. в данном случае затраты на вызов РеквизитФормыВЗначение присутствуют, но значительно больше времени уходит на каждый вызов сервера с клиента.
Бонус. Тест 3. 100 вызовов на сервере для большого документа
В документе содержится 568 строк в ТЧ Товары. Результаты замеров:
Строка |
Кол-во |
Время |
% Врем |
ТестВМодульОбъектаНаСервере(); |
1 |
16.831681 |
98.45 |
Документ = РеквизитФормыВЗначение(«Объект», Тип(«ДокументОбъект.Квотация»)); |
100 |
10.072014 |
58.91 |
ЗначениеВРеквизитФормы(Документ, «Объект»); |
100 |
3.866123 |
22.61 |
ТестВМодульФормыНаСервере(); |
1 |
0.228471 |
1.34 |
ТекущийРежим = СоединенияИБ.ПараметрыБлокировкиСеансов(); |
1 |
0.017236 |
0.10 |
ПоказатьПредупреждение(, «Завершено!»); |
1 |
0.010469 |
0.06 |
ПоказатьПредупреждение(, «Завершено!»); |
1 |
0.008086 |
0.05 |
Документ.РасширитьКомментарий(); |
100 |
0.004518 |
0.03 |
РасширитьКомментарий(); |
100 |
0.001549 |
0.01 |
Комментарий = Комментарий + «1»; |
100 |
0.001333 |
0.01 |
Объект.Комментарий = Объект.Комментарий + «1»; |
100 |
0.000767 |
0.00 |
КонецЦикла; |
100 |
0.000596 |
0.00 |
Итоги
Разумное использование связки функций РеквизитФормыВЗначение — ЗначениеВРеквизит формы более чем уместно, т.к. позволит устранить дублирование кода при относительно малых затратах (0,007-0,009 с. за вызов). Однако, использовние этой связки лучше избегать в следующих случаях:
1. Вызов осуществляется в цикле (например, при обработке ТЧ)
2. Документ имеет очень сложную структуру с одной или несколькими ТЧ, которые могут содержать несколько десятков и более записей.
СокрЛП(Статья): Стоит ли использовать РеквизитФормыВЗначение? В одних ситуация — да, в других — нет.
Я как-то считал очевидным такие накладные расходы на создание прикладного объекта из структур данных формы (ДанныеФормыСтруктура, ДанныеФормыКолекция и т.д.)
Если необходимо обеспечить работу и обычной и управляемой формы, то лучше это выносить в общий модуль с соответствующим контекстом исполнения. Тогда не будет дубликатов кода.
(2) EmpireSer, Можно, но как Вы видите передачу контекста? Другие варианты кроме передачи кучи возвращаемых параметров или структуры с необходимыми данными можете предложить? Буду признателен за конструктив
Вообще если пишете внешнюю обработку, то необходимость написать общий код в модуле объекта возрастает значительно. Но если применить хитрость, то накладные расходы будут нулевые:
1. В обработке не создавать ни каких реквизитов
2. В общей форме и в управляемой форме все необходимые реквизиты будут заданы (т.е. они будут реквизитами формы)
3. В модуле обработки методы принимают параметр «Данные», который по сути есть передача ЭтаФорма.
(3)
Контекст — это сервер, клиент (управляемые формы), клиент (обычные формы).
Просто если у Вас есть возможность написать код так, что бы использовать методы единые для объектов данных форм и прикладных объектов, то этот код можно вынести в общий модуль и его вызывать.
К примеру вот код:
Показать
Этому коду без разницы что в него подать: ТаблицаЗначений, ТабличнаяЧасть, Регистр…НаборЗаписей, ДанныеФормыКоллекция, ДанныеФормыСтруктураСКоллекцией. И Контекст не важен, т.к. у всех этих объектов метод «Добавить» существует как на клиенте так и на сервере.
Или к примеру нам нужно найти в ТабличнойЧасти объекта какие-то строки (найти номенклатуру в табличной части Товары документа), то метод «НайтиСтроки» существует и у ТабличнаяЧасть и у ДанныеФормыКоллекция. И это означает, что код может быть универсален.
Вот про что я говорил.
(5) EmpireSer, при использовании Знач ТаблицаПриемник Вы не увидите изменений в начальной таблице, разве нет? В целом идея понятна, но это упрощенный вариант. Толчком к моим размышлениям послужил метод ПриИзмененииДоговора. Вчера он, допустим, менял Валюту и КодУсловийОплаты, а завтра понадобилось дополнительно менять ДнейОтсрочки, т.е. для внесения изменений в новый реквизит. При использовании частичной передачи контекста в ОМ этот контекст придется постоянно расширять, т.е. вносить изменения не только в саму функцию, но и в каждый вызов самой функции. Это мне и не нравится
(6)
1. Про «Знач» лучше читайте ИТС. Я плохо могу объяснять разницу между объектным типом и простым.
Пример я привёл из своего общего модуля, где все методы созданы как функции для обхода отсутствия поддержки в веб-клиенте метода «Выполнить». Ну это отдельная песня…
2. Когда мне нужна супер гибкость я просто в метод общего модуля передам «ЭтаФорма» и при написании кода буду учитывать отличия между методами объектов, которые я обрабатываю. Это я Вам и предложил и тем самым Вам не нужно будет увеличивать количество передаваемых параметров в метод общего модуля.
(6) Изменений исходной таблицы не увидит, и это хорошо в данном случае. Достаточно будет возвращенного результата функции.