Уже много лет не утихают споры о полезности однострочного кода. Разберемся с этими вопросами подробно. Когда полезен однострочный код и как правильно его применять.
Интересная информация, спасибо!
Остался вопрос
Фоновые задания без флажка в автоматическом подключении отладки также запускаются в режиме разрешенной отладки?
Т.е. для кода обработчиков регламентных заданий и разных длительных операций оптимизация тоже имеет смысл?
(3) режим разрешения отладки в процессе 1С считывается только при его старте и в серверном (рабочем) процессе применяется для всех его потоков. У всех потоков внутри процесса байткод готовится и выполняется по единым правилам. Поэтому все описанное в статье также применимо и к фоновым заданиям.
Интересно конечно, но когда читаешь такие статьи - думаешь а для чего это все? Код должен быть понятен в первую очередь и экономия на спичках здесь точно не нужна. Если нам критически важна скорость - для этого есть другие языки программирования. А теперь попробуйте вспомнить в типовых конфигурациях или БСП есть однострочный код? :)
(6) писать в конфигурации однострочниками не стоит конечно. Хотя бы потому что, конечная цель конфигурации работа в "боевом" режиме. А на "боевом" сервере включать отладку вообще "такое-себе" решение. Не знаю зачем отладка на рабочем кластере может понадобится, ну разве что в крайне экстравагантных случаях.
Но кое-что полезное вынести можно. Например, если у вас есть места хранения кода в базе данных, который потенциально может быть "высокочастотным", то его можно преобразовать в однострочник и так выполнять. Буду пользоваться этим или нет не скажу, но на заметку стоит взять
(7) Бывают боевые режимы, когда конфигурация постоянно дорабатывается и регулярно приходится сталкиваться с ошибками в боевом режиме, которые в тестовой базе не воспроизводятся, а исправлять их надо срочно. В таких случаях для диагностики иметь возможность аккуратной (внутри транзакций) отладки кода очень полезно. Но разрешать или не разрешать опять же решает каждая команда для себя в зависимости от многих факторов. Утверждать что разрешение отладки в боевом режиме всегда плохо - недальновидно.
Кроме того есть много сценариев, когда на сервере разработки выполняют тяжелые задачи (например для тестирования), в которых также важна длительность выполнения. И порой на серверах разработки делают даже больше прогонов чем в боевом режиме. Поэтому там ускорение может играть даже бОльшую роль.
(9) Серега, ты опытный разработчик, спорить с тобой дело неблагодарное. Но надо ведь понимать, что дозволенное для тебя и под твоим присмотром не стоит повторять неокрепшим духом юнцам. Да и разработка бывает разной. Инхаус предполагает доступ к рабочим лошадкам, а вот аутсорс часто приводит к тому, что есть шанс никогда не увидеть живую эксплуатацию твоей системы. У нас даже данные для теста порой предоставляют в обфусцированном виде или через РДП под присмотром СБ, на машине где нет не только отладки, но банальный буфер обмена отключен.
Я просто привык так жить, поэтому (наверное) для меня нет нужды на рабочем сервере в отладке. А вот на тестовой машине что только не происходило, и с последним абзацем соглашусь безоговорочно
(11)Автора уважаю, но лично я против таких вот однострочных вставок вообще в любых конфигурациях. Минусы данного подхода перекрывают все возможные плюсы.
Для научно познавательного интереса статья подходит, а вот не оказалась бы примером для подражания. И так от кодинга типовых конфигураций кровь в жилах стынет.
Может в начале статьи сделать предупреждение: "Осторожно! Все 'трюки' выполнены профессионалами. Не повторять в реальной конфигурации")
Бывают боевые режимы, когда конфигурация постоянно дорабатывается и регулярно приходится сталкиваться с ошибками в боевом режиме, которые в тестовой базе не воспроизводятся, а исправлять их надо срочно
(50) И административный бардак, когда годами говоришь начальству, что на зоопарк из десятка боевых баз типовых конфигураций, нескольких уникальных и ещё сильно пилёная основная учётная ОДИН программист, который даже по должности не программист, а системный аналитик, и ноль поддержки кроме сисадминов - мало... но "бюджета нету"
(6)
Где я предложил писать непонятный код? Укажи конкретное место.
Экономия времени тут относительная и коэффициенты ускорения 2-6 называть "спичками" некорректно. Если выполнение занимало 6ч и мы его снизили до 1-3ч, то ощутить это смогут думаю все кроме тебя. Однако такие участки кода встречаются довольно редко, о чем в статье я опять же писал. Если выполнение занимало 60мс и мы его ускорили до 10-30мс, то применять описанный в статье прием действительно неоправданно.
Я не писал в статье, что нам критически важная скорость в целом. Я описал методику и редкие встречающиеся условия, в которых она дает существенное точечное ускорение без перехода на другие языки программирования.
Про БСП не совсем понятно. Почему именно БСП? Почему не ERP? Почему не любая другая конфигурация?
Я подробно описал возможность с ее преимуществами и всеми недостатками, проверяемую готовым тестом. Дальше каждый решает сам. Тебе она не понравилась и ты будешь применять другие языки программирования, либо просто не будешь ускорять код 1С при наличии такой возможности. Это твой выбор. Я принимаю его :)
(12) Это так. В первом разделе я описал действия, которые выполняет опкод новой строки. Проверка отладчика - самая тяжелая часть, но есть и другие легкие проверки. Они тоже занимают какое то время. Но даже для очень легких инструкций оно не превышает 10%. Поэтому я не стал его рассматривать.
(13) Я как-то число Фибоначчи вычислял, сравнивая разные стеки, так вот на 1С с отладчиком код работал 18 секунд, без отладчика 4 с чем-то, в одну строку 3,22 (т.е. 25% разницы), на питоне - 1,8, на php 0,72, на С без оптимизации 0,14, с оптимизацией -OFast 0,03, на ассемблере в развернутом целочисленном цикле (2 регистра по 64 бита на член, т.е. 128-битная арифметика) еще в 2 примерно раза быстрее. Вот как-то так.
(15) "С отладчиком" и "без отладчика" - не достаточно четкие условия. Есть 2 параметра: "подключенный отладчик" и "разрешение отладки". Что из этого входит в твои условия и как это связано с (13)?
18 747 против 14 656 миллисекунд... лучше конечно, но не принципиально... всю программу в таком стиле не напишешь...
вы, наверное, из конфигуратора под отладчиком запускали... поэтому у вас могла большая разница получиться...
Ну и вот:
ну не знаю... сейчас запустил вашу обработку FIB.epf и получил 9 644, т.е. близко к вашему результату... но все равно на секунду медленнее...
сравнил код... у вас все в одну строку, а у меня только циклы были в одну строку... и уже давало 14 656... это не 1с, а ребус какой-то... :)
Ну и вишенка на торте:
кстати, убрал пробелы - стало еще быстрее (это, кстати, на тему именования переменных - чем длиннее имя переменной, тем дольше работает 1С походу):
Ну так вперед! Расскажете потом, ибо кода проверял я, то зависимость от длинны строки некоторым образом ощущалась через измерение количества времени, потраченного на вычисления.
(36) Увы... Практика показала, что наличие пробелов и длинные имена переменных никак не влияют на быстродействие выполняемого кода. (что естественно для всех языков программирования)
(17) Загрузка контекста (метаданных) базы в рабочий процесс при разрешенной отладке выполняется плавно, т.е. мелкими порциями нужные метаданные загружаются, а при запрещенной отладке вся конфигурация целиком сразу грузится. Поэтому выполнение кода в первых соединениях базы в рабочем процессе при разрешенной отладке для больших конфигураций начинается заметно быстрее, т.к. нет длительного ожидания загрузки всей конфигурации в рабочий процесс.
(19)
Сергей, я думаю что это сильно надумано чтобы отнести к реальному сценарию, в любом случае спасибо за информацию и интересную статью. + Вам в карму и отдельное спасибо за ИР
(37) Ну я это не сам придумал. Это информация также собрана из обсуждений в партнерском форуме. Базовое утверждение (про плавную загрузку метаданных) основано на информации разработчиков платформы. Они же допустили наличие таких сценариев, а некоторые участники от партнеров подтвердили их наблюдение и даже осмысленное использование на очень больших конфигурациях (ERP).
(21) Если это не стало понятно после прочтения статьи, то наверное стоит ее еще раз прочитать, ну или скачать пример и самому его погонять. В нем можно и на сервере и на клиенте тестировать.
(24) А в чем проблема-то? Хочется поработать с комфортом? Переносим весь текст в Ворд и делаем глобальную замену ";(пробел) " на ";(перевод_строки)". Получаем вполне читаемый код. Надо вернуть? Проделываем обратную манипуляцию.
Я делал подобное в своей конфигурации для велоспорта. Там время выполнения процедур критично. Но, если честно, на практике разницы так и не почувствовал. За секунду успевал 3-х участников фиксировать как в первом случае, так и во втором.
(41) Зачем такие сложности? Если уж многострочный вариант потерян, консоль кода (ИР) умеет делать точное преобразование в обратную сторону, т.е. может восстановить оригнальный код из однострочного вида, сделанного собой.
Запрос.Выполнить().Выбрать()
Если сам результат нужен потом, то у Выборки есть метод Владелец()
2. Не нужно при выполнении условий определять лишние переменные. Т.е.:
УсловиеЗапроса = чего-то там....
Если УсловиеЗапроса Тогда...
Можно сразу написать
Если чего-то там... Тогда
Когда работал в 1С, человек отвечающий за производительность ЕРП говорил так: Если из всего ЕРП убрать лишние строки кода, то ЕРП будет работать процентов на 20 быстрее. И это даже без оптимизации запросов!
Тема не нова, почти все обфускаторы выразают (где возможно) первый оп-код. Информация носит больше академический интерес, нежели практическое применение. Если взять какой-то алгоритм из реальной жизни, то прирост от этого будет не значителен, в районе погрешностей. Т. к. основное время занимают выполнения запросов и дальнейшая постобработка данных.
Ну вот, например, есть отличный алгоритм загрузки и проверки списка недействительных паспортов, который в одну строку с минимальными именами переменных работает примерно в 2 раза быстрее, чем в несколько строк. Т.е. условно 10 минут против 20 минут на загрузку. Этот код конечен, поддерживать дальше его не надо, поэтому он вполне себе может быть написан в одну строку с переменными типа "А,Б,Ц".
Если же код написан изначально плохо и будет требовать дальнейшей поддержки, то, конечно, писать его в одну строку нельзя. Более того, чтобы он хоть внешне прилично выглядел, обязательно нужно красиво и емко именовать переменные, делать красивые вертикальные отступы (про горизонтальные вообще молчу - они должны быть в обязательном порядке), писать комментарии. И тогда код уже не будет казаться говнокодом, он будет похож на код типовых, его будет удобно поддерживать и вносить очередные красиво поименованные и с хорошими отступами костыли.
И да, я тут ни разу не иронизирую. Хорошего законченного небольшого кода, который можно написать в одну строку, вообще в мире очень мало. Остальной код, из-за принципиальной невозможности написать его предельно хорошо, нужно обязательно красиво оформлять, чтобы его дальнейшее исправление требовало меньше труда.
- это вы меня так назвали? )))) шучу.
Имхо, таких алгоритмов существует на уровне погрешностей по соотношению ко всем алгоритмам.
Не удивлюсь, что если всю типовую, например, ERP написать в 1 строку, то мы выиграем %5 по скорости, но заморочей с поддержкой такого кода отгребем более чем % на 50 )
Да все уже украдено до нас в части алгоритмов. Программист не придумывает алгоритмы (в большинстве случаев) - он использует давно уже придуманное. Чаще всего это давно придуманное весьма примитивно, но задачу решает.
Если вообще так вот посмотреть, то 1С сделала нам достаточно немало объектов/методов/функций и процедур, которые фактически уже "одна строка кода". Дальше нужно их грамотно использовать и переиспользовать. Есть несколько методологий разработки, которые определяют, как нужно переиспользовать код, в итоге программа сводится к "new app; app.run()';", но и это предпочитают писать в двух строках, а потом еще "app.done();", чтобы подчистить за собой временные файлики.
(40) Провёл небольшое исследование:
В приведенных исходниках цикл начинается на строке №15
Обратите внимание на оп-коды №№ 15, 20, 26
Из этого можно сделать вывод, что для ускорения выполнения кода достаточным условием является расположение операторов "Цикл" и "КонецЦикла" на одной строке в исходнике.
В данном примере прирост скорости на моем компе в 10 раз.
(45) Я много раз большие прогоны делал как раз на серверах разработки и тестирования, а не на проде. И сидеть без отладки на проде - такое же "тактодрочерство", т.к. в подавляющей части кода это не дает заметного ускорения, а вот невозможность отладки - весьма чувствительна в острых ситуациях. Так что каждый выбирает подход к "процессу" по обстоятельствам и вкусам.
Сделал 4 варианта оформления+компиляции кода "Решето Эратосфена" и замерил их при разешенной и запрещенной отладке. Результаты на картинке. В них заметно
1. Динамически скомпилированный код при запрещенной отладке выполняется в 2 раза медленнее даже в однострочном варианте
2. При разрешенной отладке статически скомпилированный код на 50% медленнее, чем динамически скомпилированный. Это объясняется наличием/отсутствуем возможности его отлаживать.
Ниже код теста, который надо обязательно выполнять непосредственно из модуля
Н = 1000000;
Массив = Новый Массив();
Массив.Добавить(Ложь);
Массив.Добавить(Ложь);
Для индекс = 2 По Н Цикл
Массив.Добавить(Истина);
КонецЦикла;
ирОбщий.НачатьЗамерЛкс(, "Замер1");
Для индекс = 2 По Н Цикл Если Массив[индекс] Тогда квадрат = индекс * индекс; Если квадрат <= Н Тогда м = квадрат; Пока м <= Н Цикл Массив[м] = Ложь; м = м + индекс; КонецЦикла; КонецЕсли; КонецЕсли; КонецЦикла;
ирОбщий.КончитьЗамерЛкс();
ирОбщий.НачатьЗамерЛкс(, "Замер2");
Для индекс = 2 По Н Цикл
Если Массив[индекс] Тогда
квадрат = индекс * индекс;
Если квадрат <= Н Тогда
м = квадрат;
Пока м <= Н Цикл
Массив[м] = Ложь;
м = м + индекс;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ирОбщий.КончитьЗамерЛкс();
ирОбщий.НачатьЗамерЛкс(, "Замер3");
Выполнить("Для индекс = 2 По Н Цикл Если Массив[индекс] Тогда квадрат = индекс * индекс; Если квадрат <= Н Тогда м = квадрат; Пока м <= Н Цикл Массив[м] = Ложь; м = м + индекс; КонецЦикла; КонецЕсли; КонецЕсли; КонецЦикла;
|");
ирОбщий.КончитьЗамерЛкс();
ирОбщий.НачатьЗамерЛкс(, "Замер4");
Выполнить("Для индекс = 2 По Н Цикл
| Если Массив[индекс] Тогда
| квадрат = индекс * индекс;
| Если квадрат <= Н Тогда
| м = квадрат;
| Пока м <= Н Цикл
| Массив[м] = Ложь;
| м = м + индекс;
| КонецЦикла;
| КонецЕсли;
| КонецЕсли;
|КонецЦикла;
|");
ирОбщий.КончитьЗамерЛкс();
Выполнить(
"Н = 1000000;
|Массив = Новый Массив();
|Массив.Добавить(Ложь);
|Массив.Добавить(Ложь);
|Для индекс = 2 По Н Цикл
| Массив.Добавить(Истина);
|КонецЦикла;
|ирОбщий.НачатьЗамерЛкс(, "Замер1");
|Для индекс = 2 По Н Цикл Если Массив[индекс] Тогда квадрат = индекс * индекс; Если квадрат <= Н Тогда м = квадрат; |Пока м <= Н Цикл Массив[м] = Ложь; м = м + индекс; КонецЦикла; КонецЕсли; КонецЕсли; КонецЦикла;
|ирОбщий.КончитьЗамерЛкс();
ирОбщий.НачатьЗамерЛкс(, "Замер2");
Для индекс = 2 По Н Цикл
Если Массив[индекс] Тогда
квадрат = индекс * индекс;
Если квадрат <= Н Тогда
м = квадрат;
Пока м <= Н Цикл
Массив[м] = Ложь;
м = м + индекс;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ирОбщий.КончитьЗамерЛкс();
ирОбщий.НачатьЗамерЛкс(, "Замер3");
Выполнить("Для индекс = 2 По Н Цикл Если Массив[индекс] Тогда квадрат = индекс * индекс; Если квадрат <= Н Тогда м = квадрат; Пока м <= Н Цикл Массив[м] = Ложь; м = м + индекс; КонецЦикла; КонецЕсли; КонецЕсли; КонецЦикла;
|");
ирОбщий.КончитьЗамерЛкс();
ирОбщий.НачатьЗамерЛкс(, "Замер4");
Выполнить("Для индекс = 2 По Н Цикл
| Если Массив[индекс] Тогда
| квадрат = индекс * индекс;
| Если квадрат <= Н Тогда
| м = квадрат;
| Пока м <= Н Цикл
| Массив[м] = Ложь;
| м = м + индекс;
| КонецЦикла;
| КонецЕсли;
| КонецЕсли;
|КонецЦикла;
|");
ирОбщий.КончитьЗамерЛкс();[/IS-QUOTE]
(64)
Сережа ну ей богу заниматься этой фигней чтобы что-то кому-то доказать? Познавательно - безусловно да, ты как всегда на высоте. Практическое применение? Хм... ну только если конфа с закрытым кодом... а в остальном упаси боже так код писать.
(69)
Сереж прости ради бога, не думал обидеть)
Просто применение практики однострочного кода в 1С экономически не выгодно из-за сложности отладки
Особенно на типовых конфигурациях, особенно на очень больших и сложных внедрениях.
А причину всего этого можно просто регулировать режимом отладки - если я все правильно понял.
Зачем усложнять себе код?
Зачем добавлять дополнительную обсфукацию осознано в предметно-ориентированной открытой среде разработки где главной идеологией являет максимально читаемый и понятный код даже для разработчиков не участвовавших непосредственно в разработке основной системы?
Или я не прав?
А вот к примеру применение кода вот такого вида
Если Результат=Истина Тогда
....
или конструкции вида
РезультатЗапроса = Запрос.Выполнить();
ВыборкаЗапроса = РезультатЗапроса.Выбрать();
Это не оптимальный код, но он экономически выгоден благодаря своей отказоустойчивости, контекстом локальных переменных,простоте восприятия информации, удобство работы в отладчике - и наверное самое главное - я могу очень хорошо заработать оптимизируя такой код у заказчика, если потребуется в плоть до строки вида:
Если С и Не А Или Z Тогда возврат Б.Выполнить().Выбрать() КонецЕсли;
Я к тому это веду, что любой код в 1С оптимален не всегда благодаря оптимизации быстродействия работы платформы или особенностями использования синтаксиса кода.
(60) Пока ждем ответ эксперта. Есть теория. Что в первом варианте, проверяется только на тип булево и кроме булево ничего не должно прилетать.
А во втором варианте, РезультатБулево может иметь любой тип данных и ошибки сравнения не будет.
Соответственно, больше проверок и дольше выполнение на уровне платформы.
(60) Тут все просто. Операция сравнения отсутствует в первом варианте. Поэтому во втором варианте выполняется на одну операцию больше, хоть сравнение и выполняется с константой. Зато второй вариант не требует правильного типа переменной для успешного вычисления условия.
Вот. Не удержался вставить свои 5 копеек. Во первых строках хочется поблагодарить автора за детальное исследование.
Во вторых возникла следующая мысль -
В некоторых (и даже многих) случаях повторяющийся код, даже повторяющийся в цикле код, можно заменить на процедуру (иногда на функцию) В этом случае все опять же сведется к однострочному коду, но без потери читаемости.
Интересное исследование, ничего не имею против однострочного кода, если он необходим, но методика с дублированием кода - бомба замедленного действия.
Во-первых дублирование кода это уже плохо,
во-вторых если каким-то образом однострочник будет отформатирован (линтером или юным программистом, не знакомым с методикой), то все преимущества потеряются, зато будет два одинаковых куска кода под условием, которые при чтении поставят в тупик кого угодно (о этот вечный вопрос "зачем???"),
и в третьих если кто-то в процессе жизни внесет изменения в один кусок кода, а другой не поправит - это будет очень печально.
А я, прям вижу, как в спешке в форматированном блоке изменения вносят (не исправлять же однострочник, бо он плохочитаемый, а у нас спешка), оставляют _РежимОтладки = Истина, а через некоторое время просматривая код, другой разработчик думает - о, тут по методике режим отладки обратно не вернули, а верну-ка я обратно в Ложь. И привет, старый баг.
Я думаю, что такие вещи должны решаться на уровне платформы какими-нибудь директивами препроцессора, типа #Отладка Выключить / #Отладка Включить. На уровне кода 1С бороться с этим - идея, имеющая нехорошие последствия.
Впрочем, в платформе мы этого не дождемся никогда, по очевидным причинам. Ответ будет: в проде вам отладка не нужна, а на тестах какая разница на те миллисекунды.
(72) и поворчать вдогонку. Если бы я хотел программировать на языке в котором форматирование кода определяет логику (или производительность) программы, я бы уже писал на питоне. Так что разное поведение кода при разном форматировании это ваша проблема (к разработчикам платформы), а не моя.
=)
(72)
Формально это конечно дублирование кода. Но фактически отладка и правка кода вручную выполняется только в многострочном варианте. Однострочный вариант можно лишь забыть обновить, но тут уж от тренировки зависит. Я очень редко забываю это делать.
Если есть сомнения в синхронности вариантов кода, то можно легко обновить многострочный вариант (занимает 10 секунд).
Инструкции препроцессора не позволяет переключать скорость на ходу. Поэтому я бы предложил скобки режима компиляции, т.е.
&БыстрыйКод.Начало
ф=1;
Ф=1+1;
&БыстрыйКод.Конец
тогда компилятор бы при разрешенной отладке компилировал оба варианта кода. По умолчанию выполняется однострочный вариант и все точки останова в этом блоке трактуются как точка останова на его первой строке. А когда включаем на ходу особую галку "Отладка быстрого кода", то будет выполнять многострочный код.
А вот такой код будет работать, и я вот одного не понимаю - почему я до сих пор не могу использовать параметры сеанса булевого типа для управления компиляцией кода и его бизнес логикой ?????
&НаСервере
Функция ПолучитьКонтрагента()
Возврат Неопределено
КонецФункции
&НаСервере
Функция ПолучитьДоговор()
Возврат Неопределено
КонецФункции
&НаСервере
Процедура ТестНаСервере()
//----------
#Если НЕ Версия_МоделиБизнесПроцесса_0001 Тогда
#ЕСЛИ НЕ БЫСТРЫЙ_КОД ТОГДА
Контрагент = ПолучитьКонтрагента();
#ИНАЧЕЕСЛИ БЫСТРЫЙ_КОД ТОГДА
Договор = ПолучитьДоговор();
#КОНЕЦЕСЛИ
#ИначеЕсли Версия_МоделиБизнесПроцесса_0001 Тогда
Контрагент = ПолучитьКонтрагента();
Договор = ПолучитьДоговор();
#ИначеЕсли Версия_МоделиБизнесПроцесса_0002 Тогда
Ф = 1;
#Иначе
Б = 1;
#КонецЕсли
КонецПроцедуры
&НаКлиенте
Процедура Тест(Команда)
ТестНаСервере();
КонецПроцедуры